├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .rustfmt.toml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── README.md └── bgpdumper.rs └── src ├── afi ├── evpn.rs ├── flowspec.rs ├── ipv4.rs ├── ipv6.rs ├── mac.rs ├── mdt.rs ├── mod.rs ├── mvpn.rs └── vpls.rs ├── bmp ├── bmputl.rs ├── mod.rs ├── msginit.rs ├── msgpeer.rs ├── msgrmon.rs ├── msgterm.rs └── prelude.rs ├── error.rs ├── lib.rs ├── message ├── attributes │ ├── aggregatoras.rs │ ├── aspath.rs │ ├── atomicaggregate.rs │ ├── attrset.rs │ ├── clusterlist.rs │ ├── community.rs │ ├── connector.rs │ ├── extcommunity.rs │ ├── localpref.rs │ ├── med.rs │ ├── mod.rs │ ├── multiproto.rs │ ├── nexthop.rs │ ├── origin.rs │ ├── originatorid.rs │ ├── pmsitunnelattr.rs │ └── unknown.rs ├── keepalive.rs ├── mod.rs ├── notification.rs ├── open.rs └── update │ └── mod.rs ├── prelude.rs └── util.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | **/*.bak 12 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 0.3.3 (2022-01-17) 2 | 3 | #### Features 4 | * log crate using 5 | * unknown capability ignore 6 | 7 | #### Fixes 8 | * aggregatoras attribute adaptive for BMP 9 | 10 | ### 0.3.2 (2022-01-17) 11 | 12 | #### Features 13 | * BMP decode route monitoring with parameters from previously caught BGP OPEN messages 14 | * Support for addpath detection for BMP route monitoring 15 | 16 | ### 0.3.1 (2022-01-16) 17 | 18 | #### Fixes 19 | * fixed panic on invalid ipv6 record length 20 | 21 | ### 0.3.0 (2022-10-08) 22 | 23 | #### Features 24 | 25 | * serde deserializaion support 26 | * mdt safi (multicast distribution tree) added 27 | 28 | #### Fixes 29 | 30 | * clippy fixes 31 | 32 | ### 0.2.1 (2021-08-01) 33 | 34 | #### Features 35 | 36 | * multiple AddPath capabilities support 37 | 38 | ### 0.2.0 (2021-07-25) 39 | 40 | #### Features 41 | 42 | * AddPath support 43 | * afi::BgpNet support for MAC prefixes 44 | * extcommunity varieties extended 45 | 46 | ### 0.1.5 (2021-07-19) 47 | 48 | #### Features 49 | 50 | * examples added 51 | 52 | #### Fixes 53 | 54 | * many extra buffer checks 55 | 56 | ### 0.1.4 (2021-07-14) 57 | 58 | #### Features 59 | 60 | * EVPN display improved, MacAddress display improved. ([83ac56c]https://github.com/wladwm/zettabgp/commit/83ac56ce9af94d628877f48fc7b3f9be4cb05200)) 61 | 62 | ### 0.1.3 (2021-07-13) 63 | 64 | #### Fixes 65 | 66 | * fixed EVPN encoding. ([cfc9bc1](https://github.com/wladwm/zettabgp/commit/cfc9bc1b47287cfe7e37d6fdbe9644d6cb3a69cc)) 67 | 68 | ### 0.1.2 (2021-05-23) 69 | 70 | #### Features 71 | 72 | * **BgpError:** add a too_many_data() constructor to BgpError. ([9913afb](https://github.com/wladwm/zettabgp/commit/9913afb635c1120acdeb92ece1bcc4eba43edf3a)) 73 | * **BgpNet:** added utility struct BgpNet - like std::net::IpAddr but with prefix len. ([713563a](https://github.com/wladwm/zettabgp/commit/713563a5d5771fb53f1f4afeba88a6ebfa158e6f)) 74 | * **BgpExtCommunity:** added rt_ipn contructor for extended community route target IPv4:N. ([791af48](https://github.com/wladwm/zettabgp/commit/791af4804c0639bf5b5109a9591200983ce4cf0f)) 75 | * Fixed MP withdraws encoding. ([2db5497](https://github.com/wladwm/zettabgp/commit/2db54977439a3051d05f5c54f7db6fcb36ecf5b8)) 76 | 77 | #### Fixes 78 | 79 | * **BgpASpath:** fixed encoding. ([f85c4b8](https://github.com/wladwm/zettabgp/commit/f85c4b86f67b2c8b8c5f0b3d441b15cb6122b705)) 80 | * Methods descriptions fixed on ipv4 and ipv6 nets ([4b10770](https://github.com/wladwm/zettabgp/commit/4b10770493cd08ac9751079e65de35e0f63a7e81)) 81 | 82 | ### 0.1.1 (2021-05-04) 83 | 84 | Fixed descriptions and readme 85 | 86 | ### 0.0.1 (2021-05-04) 87 | 88 | First release 89 | 90 | 91 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zettabgp" 3 | version = "0.3.4" 4 | authors = ["Vladimir Melnikov "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/wladwm/zettabgp" 8 | keywords = ["BGP"] 9 | categories = ["network-programming","encoding","data-structures"] 10 | description = "This is a BGP (parsing and composing) and BMP (only parsing) protocols driver library for Rust" 11 | readme = "README.md" 12 | 13 | [features] 14 | default = ["serialization"] 15 | serialization = ["serde"] 16 | 17 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 18 | 19 | [dependencies] 20 | log = "0.4.17" 21 | serde = { version="1.0", features = ["derive"], optional = true } 22 | 23 | [dev-dependencies] 24 | env_logger = "0.10.0" 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Vladimir Melnikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | zettabgp - BGP&BMP Rust library 2 | ==================== 3 | 4 | This is a BGP and BMP protocols driver library for Rust. 5 | 6 | BGP - Border Gateway Protocol version 4. 7 | BMP - BGP Monitoring Protocol version 3. 8 | 9 | ## Supported BGP message types 10 | * Open 11 | * Notification 12 | * Keepalive 13 | * Update 14 | 15 | ## Supported BMP message types 16 | * Initiation 17 | * Termination 18 | * PeerUpNotification 19 | * RouteMonitoring 20 | 21 | ## Supported address families NLRI (network layer reachability information) 22 | * ipv4 unicast 23 | * ipv4 labeled-unicast 24 | * ipv4 multicast 25 | * ipv4 mvpn 26 | * ipv4 mdt 27 | * vpnv4 unicast 28 | * vpnv4 multicast 29 | * ipv6 unicast 30 | * ipv6 labeled-unicast 31 | * ipv6 multicast 32 | * ipv6 mdt 33 | * vpnv6 unicast 34 | * vpnv6 multicast 35 | * vpls 36 | * evpn 37 | * flowspec ipv4 38 | * flowspec ipv6 39 | 40 | ## Supported path attributes 41 | * MED 42 | * Origin 43 | * Local preference 44 | * AS path 45 | * Communities 46 | * Extended communities 47 | * Aggregator AS 48 | * Atomic aggregate 49 | * Cluster list 50 | * Originator ID 51 | * Attribute set 52 | * Connector 53 | * some PMSI tunnels 54 | 55 | ## Usage 56 | 57 | Library allow you to parse protocol messages (as binary buffers) into Rust data structures to frther processing. 58 | Or generate valid protocol messages from Rust data structure. 59 | So it can be use in any environment (synrchronous or asynchronous) to make a BGP RR, monitoring system or BGP analytics. 60 | 61 | ```rust 62 | use zettabgp::prelude::*; 63 | use std::io::{Read,Write}; 64 | let mut socket = match std::net::TcpStream::connect("127.0.0.1:179") { 65 | Ok(sck) => sck, 66 | Err(e) => {eprintln!("Unable to connect to BGP neighbor: {}",e);return;} 67 | }; 68 | let params=BgpSessionParams::new(64512,180,BgpTransportMode::IPv4,std::net::Ipv4Addr::new(1,1,1,1),vec![BgpCapability::SafiIPv4u].into_iter().collect()); 69 | let mut buf = [0 as u8; 32768]; 70 | let mut open_my = params.open_message(); 71 | let open_sz = open_my.encode_to(¶ms, &mut buf[19..]).unwrap(); 72 | let tosend = params.prepare_message_buf(&mut buf, BgpMessageType::Open, open_sz).unwrap(); 73 | socket.write_all(&buf[0..tosend]).unwrap();//send my open message 74 | socket.read_exact(&mut buf[0..19]).unwrap();//read response message head 75 | let messagehead=params.decode_message_head(&buf).unwrap();//decode message head 76 | if messagehead.0 == BgpMessageType::Open { 77 | socket.read_exact(&mut buf[0..messagehead.1]).unwrap();//read message body 78 | let mut bom = BgpOpenMessage::new(); 79 | bom.decode_from(¶ms, &buf[0..messagehead.1]).unwrap();//decode received message body 80 | eprintln!("BGP Open message received: {:?}", bom); 81 | } 82 | ``` 83 | 84 | 85 | ## Crates.io 86 | 87 | https://crates.io/crates/zettabgp 88 | 89 | ## Documentation 90 | 91 | https://docs.rs/zettabgp 92 | 93 | ## License 94 | 95 | [MIT OR Apache-2.0](LICENSE) -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Example of using zettabgp 2 | 3 | If you checkout this repository, you can build any of the examples (at this time - only bgpdumper) `cargo run --example example_name`. 4 | 5 | ### Dependencies 6 | 7 | ```toml 8 | [dependencies] 9 | zettabgp = { version = "0.1.4", features = ["full"] } 10 | ``` 11 | 12 | ## Getting Started 13 | 14 | ### Minimal BGP dumper 15 | 16 | * [`bgpdumper`](bgpdumper.rs) - A simple CLI application connects to specified BGP peer and prints incoming messages. Of course you should configure your BGP router first. 17 | -------------------------------------------------------------------------------- /examples/bgpdumper.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This is an example of usage zettabgp. 10 | //! Application connects to specified BGP peer and prints incoming messages 11 | 12 | extern crate zettabgp; 13 | 14 | use std::env; 15 | use std::io::{Read, Write}; 16 | use std::net::{Shutdown, TcpStream}; 17 | use std::thread::{sleep, spawn}; 18 | use zettabgp::prelude::*; 19 | 20 | pub struct BgpDumper { 21 | pub params: BgpSessionParams, 22 | pub stream: TcpStream, 23 | } 24 | impl BgpDumper { 25 | pub fn new(bgp_params: BgpSessionParams, tcpstream: TcpStream) -> BgpDumper { 26 | BgpDumper { 27 | params: bgp_params, 28 | stream: tcpstream, 29 | } 30 | } 31 | fn recv_message_head(&mut self) -> Result<(BgpMessageType, usize), BgpError> { 32 | let mut buf = [0_u8; 19]; 33 | self.stream.read_exact(&mut buf)?; 34 | self.params.decode_message_head(&buf) 35 | } 36 | pub fn start_active(&mut self) -> Result<(), BgpError> { 37 | let mut bom = self.params.open_message(); 38 | let mut buf = [255_u8; 4096]; 39 | let messagelen = match bom.encode_to(&self.params, &mut buf[19..]) { 40 | Err(e) => { 41 | return Err(e); 42 | } 43 | Ok(sz) => sz, 44 | }; 45 | let blen = self 46 | .params 47 | .prepare_message_buf(&mut buf, BgpMessageType::Open, messagelen)?; 48 | self.stream.write_all(&buf[0..blen])?; 49 | let msg = match self.recv_message_head() { 50 | Err(e) => { 51 | return Err(e); 52 | } 53 | Ok(msg) => msg, 54 | }; 55 | if msg.0 != BgpMessageType::Open { 56 | return Err(BgpError::static_str("Invalid state to start_active")); 57 | } 58 | self.stream.read_exact(&mut buf[0..msg.1])?; 59 | bom.decode_from(&self.params, &buf[0..msg.1])?; 60 | self.params.hold_time = bom.hold_time; 61 | self.params.caps = bom.caps; 62 | self.params.check_caps(); 63 | Ok(()) 64 | } 65 | pub fn send_keepalive(stream: &mut TcpStream) -> Result<(), BgpError> { 66 | let mut buf = [255_u8; 19]; 67 | buf[0..16].clone_from_slice(&[255_u8; 16]); 68 | buf[16] = 0; 69 | buf[17] = 19; 70 | buf[18] = 4; //keepalive 71 | match stream.write_all(&buf) { 72 | Ok(_) => Ok(()), 73 | Err(e) => Err(e.into()), 74 | } 75 | } 76 | pub fn start_keepalives(&self) -> Result<(), BgpError> { 77 | let mut ks = self.stream.try_clone()?; 78 | let slp = std::time::Duration::new((self.params.hold_time / 3) as u64, 0); 79 | spawn(move || loop { 80 | if BgpDumper::send_keepalive(&mut ks).is_err() { 81 | break; 82 | } 83 | sleep(slp); 84 | }); 85 | Ok(()) 86 | } 87 | pub fn lifecycle(&mut self) -> Result<(), BgpError> { 88 | self.start_keepalives()?; 89 | let mut buf = Box::new([0_u8; 65536]); 90 | loop { 91 | let msg = match self.recv_message_head() { 92 | Ok(m) => m, 93 | Err(e) => { 94 | return Err(e); 95 | } 96 | }; 97 | if msg.0 == BgpMessageType::Keepalive { 98 | continue; 99 | } 100 | self.stream.read_exact(&mut buf[0..msg.1])?; 101 | match msg.0 { 102 | BgpMessageType::Open => { 103 | eprintln!("Incorrect open message!"); 104 | break; 105 | } 106 | BgpMessageType::Keepalive => {} 107 | BgpMessageType::Notification => { 108 | let mut msgnotification = BgpNotificationMessage::new(); 109 | match msgnotification.decode_from(&self.params, &buf[0..msg.1]) { 110 | Err(e) => { 111 | eprintln!("BGP notification decode error: {:?}", e); 112 | } 113 | Ok(_) => { 114 | println!( 115 | "BGP notification: {:?} - {:?}", 116 | msgnotification, 117 | msgnotification.error_text() 118 | ); 119 | } 120 | }; 121 | break; 122 | } 123 | BgpMessageType::Update => { 124 | let mut msgupdate = BgpUpdateMessage::new(); 125 | if let Err(e) = msgupdate.decode_from(&self.params, &buf[0..msg.1]) { 126 | eprintln!("BGP update decode error: {:?}", e); 127 | continue; 128 | } 129 | println!("{:?}", msgupdate); 130 | } 131 | } 132 | } 133 | Ok(()) 134 | } 135 | pub fn close(&mut self) { 136 | self.stream.shutdown(Shutdown::Both).unwrap_or_default(); 137 | } 138 | } 139 | 140 | fn main() { 141 | env_logger::init(); 142 | if env::args().len() != 3 { 143 | eprintln!("Usage: bgpdumper PEER AS"); 144 | return; 145 | } 146 | let vargs: Vec = env::args().collect(); 147 | let targetip: std::net::IpAddr = match vargs[1].parse() { 148 | Ok(x) => x, 149 | Err(_) => { 150 | eprintln!("Invalid peer IP - {}", vargs[1]); 151 | return; 152 | } 153 | }; 154 | let targetasn: u32 = match vargs[2].parse() { 155 | Ok(x) => x, 156 | Err(_) => { 157 | eprintln!("Invalid peer ASn - {}", vargs[2]); 158 | return; 159 | } 160 | }; 161 | let target = std::net::SocketAddr::new(targetip, 179); 162 | let stream = std::net::TcpStream::connect(target).expect("Unable to connect to bgp speaker"); 163 | let mut peer = BgpDumper::new( 164 | BgpSessionParams::new( 165 | targetasn, 166 | 180, 167 | BgpTransportMode::IPv4, 168 | std::net::Ipv4Addr::new(1, 0, 0, 0), 169 | vec![ 170 | BgpCapability::SafiIPv4u, 171 | BgpCapability::SafiIPv4m, 172 | BgpCapability::SafiIPv4lu, 173 | BgpCapability::SafiIPv6lu, 174 | BgpCapability::SafiVPNv4u, 175 | BgpCapability::SafiVPNv4m, 176 | BgpCapability::SafiVPNv6u, 177 | BgpCapability::SafiVPNv6m, 178 | BgpCapability::SafiIPv4mvpn, 179 | BgpCapability::SafiVPLS, 180 | BgpCapability::CapRR, 181 | BgpCapability::CapASN32(targetasn), 182 | ] 183 | .into_iter() 184 | .collect(), 185 | ), 186 | stream, 187 | ); 188 | if let Err(e) = peer.start_active() { 189 | eprintln!("failed to create BGP peer; err = {:?}", e); 190 | peer.close(); 191 | return; 192 | }; 193 | println!("Run lifecycle"); 194 | peer.lifecycle().unwrap(); 195 | println!("Done lifecycle"); 196 | peer.close(); 197 | } 198 | -------------------------------------------------------------------------------- /src/afi/ipv4.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module describes NLRI data structures for ipv4 10 | 11 | use crate::afi::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::default::Default; 15 | use std::net::Ipv4Addr; 16 | 17 | /// ipv4 prefix unicast/multicast NLRI 18 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 19 | #[cfg(feature = "serialization")] 20 | #[derive(Serialize, Deserialize)] 21 | pub struct BgpAddrV4 { 22 | /// network prefix 23 | pub addr: Ipv4Addr, 24 | /// prefix length 0..32 25 | pub prefixlen: u8, 26 | } 27 | impl Default for BgpAddrV4 { 28 | fn default() -> Self { 29 | BgpAddrV4 { 30 | addr: Ipv4Addr::new(127, 0, 0, 1), 31 | prefixlen: 32, 32 | } 33 | } 34 | } 35 | impl BgpAddrV4 { 36 | /// Constructs new ipv4 prefix 37 | /// ``` 38 | /// use zettabgp::prelude::BgpAddrV4; 39 | /// use std::net::Ipv4Addr; 40 | /// 41 | /// let pfx = BgpAddrV4::new(Ipv4Addr::new(192,168,0,0),16); 42 | /// ``` 43 | pub fn new(address: Ipv4Addr, prefix_len: u8) -> BgpAddrV4 { 44 | BgpAddrV4 { 45 | addr: address, 46 | prefixlen: prefix_len, 47 | } 48 | } 49 | fn norm_subnet_u32(&self) -> u32 { 50 | getn_u32(&self.addr.octets()) & (((1 << (32 - self.prefixlen)) - 1) ^ 0xffffffff) 51 | } 52 | /// Check if IP in subnet 53 | /// ``` 54 | /// use zettabgp::prelude::BgpAddrV4; 55 | /// use std::net::Ipv4Addr; 56 | /// 57 | /// assert!(BgpAddrV4::new(Ipv4Addr::new(192,168,0,0),16).in_subnet(&Ipv4Addr::new(192,168,0,1))) 58 | /// ``` 59 | pub fn in_subnet(&self, a: &Ipv4Addr) -> bool { 60 | if self.prefixlen == 0 { 61 | true 62 | } else if self.prefixlen > 31 { 63 | getn_u32(&self.addr.octets()) == getn_u32(&a.octets()) 64 | } else { 65 | let lv = self.norm_subnet_u32(); 66 | let lh = lv + ((1 << (32 - self.prefixlen)) - 1); 67 | let va = getn_u32(&a.octets()); 68 | (va >= lv) && (va <= lh) 69 | } 70 | } 71 | /// Returns first IP address (network address) from subnet 72 | /// ``` 73 | /// use std::net::Ipv4Addr; 74 | /// use zettabgp::prelude::BgpAddrV4; 75 | /// 76 | /// assert_eq!(BgpAddrV4::new(Ipv4Addr::new(192,168,120,130),16).range_first() , Ipv4Addr::new(192,168,0,0) ); 77 | /// ``` 78 | pub fn range_first(&self) -> Ipv4Addr { 79 | let lv = self.norm_subnet_u32(); 80 | Ipv4Addr::new( 81 | (lv >> 24) as u8, 82 | (lv >> 16) as u8, 83 | (lv >> 8) as u8, 84 | (lv & 0xff) as u8, 85 | ) 86 | } 87 | /// Returns last inclusive IP address for subnet 88 | /// ``` 89 | /// use std::net::Ipv4Addr; 90 | /// use zettabgp::prelude::BgpAddrV4; 91 | /// 92 | /// assert_eq!(BgpAddrV4::new(Ipv4Addr::new(192,168,120,130),16).range_last() , Ipv4Addr::new(192,168,255,255) ); 93 | /// ``` 94 | pub fn range_last(&self) -> std::net::Ipv4Addr { 95 | if self.prefixlen < 1 { 96 | std::net::Ipv4Addr::new(255, 255, 255, 255) 97 | } else if self.prefixlen > 31 { 98 | self.range_first() 99 | } else { 100 | let lv = self.norm_subnet_u32() + ((1 << (32 - self.prefixlen)) - 1); 101 | std::net::Ipv4Addr::new( 102 | (lv >> 24) as u8, 103 | (lv >> 16) as u8, 104 | (lv >> 8) as u8, 105 | (lv & 0xff) as u8, 106 | ) 107 | } 108 | } 109 | /// Check if given subnet is in this subnet 110 | /// ``` 111 | /// use std::net::Ipv4Addr; 112 | /// use zettabgp::prelude::BgpAddrV4; 113 | /// 114 | /// assert!(BgpAddrV4::new(Ipv4Addr::new(192,168,0,0),16).contains(&BgpAddrV4::new(Ipv4Addr::new(192,168,0,0),24))); 115 | /// ``` 116 | pub fn contains(&self, a: &BgpAddrV4) -> bool { 117 | if self.prefixlen < 1 { 118 | true 119 | } else if self.prefixlen > a.prefixlen { 120 | false 121 | } else if self.prefixlen == a.prefixlen { 122 | self.addr == a.addr 123 | } else { 124 | self.in_subnet(&a.range_first()) && self.in_subnet(&a.range_last()) 125 | } 126 | } 127 | /// Check if given address is multicast 128 | pub fn is_multicast(&self) -> bool { 129 | (self.addr.octets() != [255, 255, 255, 255]) && self.addr.octets()[0] >= 224 130 | } 131 | pub fn from_bits(bits: u8, buf: &[u8]) -> Result<(BgpAddrV4, usize), BgpError> { 132 | let bytes = ((bits + 7) / 8) as usize; 133 | if bits > 32 || buf.len() < bytes { 134 | return Err(BgpError::from_string(format!( 135 | "Invalid ipv4 FEC length: {:?}", 136 | bits 137 | ))); 138 | } 139 | let mut bf = [0_u8; 4]; 140 | if bits == 0 { 141 | return Ok(( 142 | BgpAddrV4 { 143 | addr: decode_addrv4_from(&bf)?, 144 | prefixlen: 0, 145 | }, 146 | 0, 147 | )); 148 | } 149 | bf[0..bytes].clone_from_slice(&buf[0..bytes]); 150 | Ok(( 151 | BgpAddrV4 { 152 | addr: decode_addrv4_from(&bf)?, 153 | prefixlen: bits, 154 | }, 155 | bytes, 156 | )) 157 | } 158 | pub fn to_bits(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { 159 | if self.prefixlen == 0 { 160 | return Ok((0, 0)); 161 | } 162 | let mut bf = [0_u8; 4]; 163 | bf.clone_from_slice(&self.addr.octets()); 164 | let bytes = ((self.prefixlen + 7) / 8) as usize; 165 | buf[0..bytes].clone_from_slice(&bf[0..bytes]); 166 | Ok((self.prefixlen, bytes)) 167 | } 168 | } 169 | impl std::str::FromStr for BgpAddrV4 { 170 | type Err = std::net::AddrParseError; 171 | 172 | fn from_str(s: &str) -> Result { 173 | let parts: Vec<&str> = s.split('/').collect(); 174 | if parts.len() < 2 { 175 | Ok(BgpAddrV4 { 176 | addr: parts[0].parse::()?, 177 | prefixlen: 32, 178 | }) 179 | } else { 180 | Ok(BgpAddrV4 { 181 | addr: parts[0].parse::()?, 182 | prefixlen: parts[1].parse::().unwrap_or(32), 183 | }) 184 | } 185 | } 186 | } 187 | impl BgpItem for BgpAddrV4 { 188 | fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpAddrV4, usize), BgpError> { 189 | BgpAddrV4::from_bits(bits, buf) 190 | } 191 | fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { 192 | self.to_bits(buf) 193 | } 194 | fn prefixlen(&self) -> usize { 195 | self.prefixlen as usize 196 | } 197 | } 198 | impl std::fmt::Display for BgpAddrV4 { 199 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 200 | write!(f, "{}/{}", self.addr, self.prefixlen) 201 | } 202 | } 203 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 204 | #[cfg(feature = "serialization")] 205 | #[derive(Serialize, Deserialize)] 206 | pub struct BgpIPv4RD { 207 | pub rd: BgpRD, 208 | pub addr: std::net::Ipv4Addr, 209 | } 210 | impl BgpIPv4RD { 211 | pub fn new(crd: BgpRD, adr: std::net::Ipv4Addr) -> BgpIPv4RD { 212 | BgpIPv4RD { rd: crd, addr: adr } 213 | } 214 | } 215 | impl std::fmt::Display for BgpIPv4RD { 216 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 217 | if self.rd.is_zero() { 218 | self.addr.fmt(f) 219 | } else { 220 | write!(f, "<{}>{}", self.rd, self.addr) 221 | } 222 | } 223 | } 224 | impl BgpAddrItem for BgpIPv4RD { 225 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpIPv4RD, usize), BgpError> { 226 | if buf.len() >= 12 { 227 | let p = BgpRD::decode_from(mode, &buf[0..8])?; 228 | Ok(( 229 | BgpIPv4RD { 230 | rd: p.0, 231 | addr: match decode_addr_from(&buf[(p.1)..(p.1 + 4)])? { 232 | std::net::IpAddr::V4(n) => n, 233 | _ => return Err(BgpError::static_str("Invalid address kind")), 234 | }, 235 | }, 236 | p.1 + 4, 237 | )) 238 | } else { 239 | Err(BgpError::static_str("Invalid BgpIPv4RD buffer len")) 240 | } 241 | } 242 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 243 | let pos = self.rd.encode_to(mode, buf)?; 244 | let p2 = encode_addrv4_to(&self.addr, &mut buf[pos..])?; 245 | Ok(pos + p2) 246 | } 247 | } 248 | 249 | #[cfg(test)] 250 | mod tests { 251 | use super::*; 252 | 253 | #[test] 254 | fn test_ipv4_parse() { 255 | assert_eq!( 256 | "10.0.0.0".parse::(), 257 | Ok(BgpAddrV4::new(Ipv4Addr::new(10, 0, 0, 0), 32)) 258 | ); 259 | assert_eq!( 260 | "10.0.0.0/8".parse::(), 261 | Ok(BgpAddrV4::new(Ipv4Addr::new(10, 0, 0, 0), 8)) 262 | ); 263 | } 264 | 265 | #[test] 266 | fn test_ipv4_in_subnet() { 267 | assert!(BgpAddrV4::new(Ipv4Addr::new(192, 168, 0, 0), 16) 268 | .in_subnet(&Ipv4Addr::new(192, 168, 0, 1))); 269 | assert!(BgpAddrV4::new(Ipv4Addr::new(192, 168, 0, 0), 16) 270 | .contains(&BgpAddrV4::new(Ipv4Addr::new(192, 168, 0, 0), 24))); 271 | } 272 | #[test] 273 | fn test_ipv4_ranges() { 274 | assert_eq!( 275 | BgpAddrV4::new(Ipv4Addr::new(192, 168, 120, 130), 16).range_first(), 276 | Ipv4Addr::new(192, 168, 0, 0) 277 | ); 278 | assert_eq!( 279 | BgpAddrV4::new(Ipv4Addr::new(192, 168, 120, 130), 16).range_last(), 280 | Ipv4Addr::new(192, 168, 255, 255) 281 | ); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/afi/ipv6.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module describes NLRI data structures for ipv6 10 | 11 | use crate::afi::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::net::Ipv6Addr; 15 | 16 | /// ipv6 prefix unicast/multicast NLRI 17 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 18 | #[cfg(feature = "serialization")] 19 | #[derive(Serialize, Deserialize)] 20 | pub struct BgpAddrV6 { 21 | /// network prefix 22 | pub addr: Ipv6Addr, 23 | /// prefix length 0..128 24 | pub prefixlen: u8, 25 | } 26 | impl Default for BgpAddrV6 { 27 | fn default() -> Self { 28 | BgpAddrV6 { 29 | addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 30 | prefixlen: 128, 31 | } 32 | } 33 | } 34 | impl BgpAddrV6 { 35 | /// Constructs new ipv6 prefix 36 | /// ``` 37 | /// use std::net::Ipv6Addr; 38 | /// use zettabgp::prelude::BgpAddrV6; 39 | /// 40 | /// let pfx = BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0),32); 41 | /// ``` 42 | pub fn new(address: Ipv6Addr, prefix_len: u8) -> BgpAddrV6 { 43 | BgpAddrV6 { 44 | addr: address, 45 | prefixlen: prefix_len, 46 | } 47 | } 48 | /// if given subnet is in this subnet 49 | /// ``` 50 | /// use std::net::Ipv6Addr; 51 | /// use zettabgp::prelude::BgpAddrV6; 52 | /// 53 | /// assert!(BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0),32).contains(&BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,1),128))); 54 | /// ``` 55 | pub fn contains(&self, a: &BgpAddrV6) -> bool { 56 | if self.prefixlen < 1 { 57 | true 58 | } else if self.prefixlen > a.prefixlen { 59 | false 60 | } else if self.prefixlen == a.prefixlen { 61 | self.addr == a.addr 62 | } else { 63 | (getn_u128(&self.addr.octets()) & (!((1 << (128 - self.prefixlen)) - 1))) 64 | == (getn_u128(&a.addr.octets()) & (!((1 << (128 - self.prefixlen)) - 1))) 65 | } 66 | } 67 | fn norm_subnet_u128(&self) -> u128 { 68 | getn_u128(&self.addr.octets()) 69 | & (((1 << (128 - self.prefixlen)) - 1) ^ 0xffffffffffffffffffffffffffffffff) 70 | } 71 | /// Check if IP in this subnet 72 | /// ``` 73 | /// use zettabgp::prelude::BgpAddrV6; 74 | /// use std::net::Ipv6Addr; 75 | /// 76 | /// assert!(BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0),32).in_subnet(&Ipv6Addr::new(0x2a02,0,0,0,0,0,0,1))); 77 | /// ``` 78 | pub fn in_subnet(&self, a: &std::net::Ipv6Addr) -> bool { 79 | if self.prefixlen > 127 { 80 | getn_u128(&self.addr.octets()) == getn_u128(&a.octets()) 81 | } else { 82 | let lv = self.norm_subnet_u128(); 83 | let lh = lv + ((1 << (128 - self.prefixlen)) - 1); 84 | let va = getn_u128(&a.octets()); 85 | (va >= lv) && (va < lh) 86 | } 87 | } 88 | /// Returns first IP address (network address) from subnet 89 | /// ``` 90 | /// use std::net::Ipv6Addr; 91 | /// use zettabgp::prelude::BgpAddrV6; 92 | /// 93 | /// assert_eq!(BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0x100),32).range_first() , Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0) ); 94 | /// ``` 95 | pub fn range_first(&self) -> std::net::Ipv6Addr { 96 | let lv = self.norm_subnet_u128(); 97 | std::net::Ipv6Addr::new( 98 | (lv >> 112) as u16, 99 | (lv >> 96) as u16, 100 | (lv >> 80) as u16, 101 | (lv >> 64) as u16, 102 | (lv >> 48) as u16, 103 | (lv >> 32) as u16, 104 | (lv >> 16) as u16, 105 | (lv & 0xffff) as u16, 106 | ) 107 | } 108 | /// Returns last inclusive IP address for subnet 109 | /// ``` 110 | /// use std::net::Ipv6Addr; 111 | /// use zettabgp::prelude::BgpAddrV6; 112 | /// 113 | /// assert_eq!(BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0x100),112).range_last() , Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0xffff) ); 114 | /// ``` 115 | pub fn range_last(&self) -> std::net::Ipv6Addr { 116 | if self.prefixlen < 1 { 117 | std::net::Ipv6Addr::new( 118 | 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 119 | ) 120 | } else if self.prefixlen > 127 { 121 | self.range_first() 122 | } else { 123 | let lv = self.norm_subnet_u128() + ((1 << (128 - self.prefixlen)) - 1); 124 | std::net::Ipv6Addr::new( 125 | (lv >> 112) as u16, 126 | (lv >> 96) as u16, 127 | (lv >> 80) as u16, 128 | (lv >> 64) as u16, 129 | (lv >> 48) as u16, 130 | (lv >> 32) as u16, 131 | (lv >> 16) as u16, 132 | (lv & 0xffff) as u16, 133 | ) 134 | } 135 | } 136 | /// Check if given address is multicast 137 | pub fn is_multicast(&self) -> bool { 138 | self.addr.octets()[0] == 255 139 | } 140 | pub fn from_bits(bits: u8, buf: &[u8]) -> Result<(BgpAddrV6, usize), BgpError> { 141 | let bytes = ((bits + 7) / 8) as usize; 142 | if bits > 128 || buf.len() < bytes { 143 | return Err(BgpError::from_string(format!( 144 | "Invalid ipv6 FEC length: {:?}", 145 | bits 146 | ))); 147 | } 148 | let mut bf = [0_u8; 16]; 149 | if bits == 0 { 150 | return Ok(( 151 | BgpAddrV6 { 152 | addr: decode_addrv6_from(&bf)?, 153 | prefixlen: 0, 154 | }, 155 | 0, 156 | )); 157 | } 158 | bf[0..bytes].clone_from_slice(&buf[0..bytes]); 159 | Ok(( 160 | BgpAddrV6 { 161 | addr: decode_addrv6_from(&bf)?, 162 | prefixlen: bits, 163 | }, 164 | bytes, 165 | )) 166 | } 167 | pub fn to_bits(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { 168 | if self.prefixlen == 0 { 169 | return Ok((0, 0)); 170 | } 171 | let mut bf = [0_u8; 16]; 172 | bf.clone_from_slice(&self.addr.octets()); 173 | let bytes = ((self.prefixlen + 7) / 8) as usize; 174 | buf[0..bytes].clone_from_slice(&bf[0..bytes]); 175 | Ok((self.prefixlen, bytes)) 176 | } 177 | } 178 | impl std::str::FromStr for BgpAddrV6 { 179 | type Err = std::net::AddrParseError; 180 | 181 | fn from_str(s: &str) -> Result { 182 | let parts: Vec<&str> = s.split('/').collect(); 183 | if parts.len() < 2 { 184 | Ok(BgpAddrV6 { 185 | addr: parts[0].parse::()?, 186 | prefixlen: 128, 187 | }) 188 | } else { 189 | Ok(BgpAddrV6 { 190 | addr: parts[0].parse::()?, 191 | prefixlen: parts[1].parse::().unwrap_or(128), 192 | }) 193 | } 194 | } 195 | } 196 | impl BgpItem for BgpAddrV6 { 197 | fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpAddrV6, usize), BgpError> { 198 | BgpAddrV6::from_bits(bits, buf) 199 | } 200 | fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { 201 | self.to_bits(buf) 202 | } 203 | fn prefixlen(&self) -> usize { 204 | self.prefixlen as usize 205 | } 206 | } 207 | impl std::fmt::Display for BgpAddrV6 { 208 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 209 | write!(f, "{:?}/{:?}", self.addr, self.prefixlen) 210 | } 211 | } 212 | 213 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 214 | #[cfg(feature = "serialization")] 215 | #[derive(Serialize, Deserialize)] 216 | pub struct BgpIPv6RD { 217 | pub rd: BgpRD, 218 | pub addr: std::net::Ipv6Addr, 219 | } 220 | impl std::fmt::Display for BgpIPv6RD { 221 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 222 | if self.rd.is_zero() { 223 | self.addr.fmt(f) 224 | } else { 225 | write!(f, "<{}>{}", self.rd, self.addr) 226 | } 227 | } 228 | } 229 | impl BgpAddrItem for BgpIPv6RD { 230 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpIPv6RD, usize), BgpError> { 231 | if buf.len() >= 24 { 232 | let rdp = BgpRD::decode_from(mode, &buf[0..8])?; 233 | Ok(( 234 | BgpIPv6RD { 235 | rd: rdp.0, 236 | addr: match decode_addr_from(&buf[(rdp.1)..(rdp.1 + 16)])? { 237 | std::net::IpAddr::V6(n) => n, 238 | _ => return Err(BgpError::static_str("Invalid address kind")), 239 | }, 240 | }, 241 | rdp.1 + 16, 242 | )) 243 | } else { 244 | Err(BgpError::static_str("Invalid BgpIPv6RD buffer len")) 245 | } 246 | } 247 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 248 | let pos = self.rd.encode_to(mode, buf)?; 249 | let p2 = encode_addrv6_to(&self.addr, &mut buf[pos..])?; 250 | Ok(pos + p2) 251 | } 252 | } 253 | #[cfg(test)] 254 | mod tests { 255 | use super::*; 256 | 257 | #[test] 258 | fn test_ipv6_parse() { 259 | assert_eq!( 260 | "2a02::/32".parse::(), 261 | Ok(BgpAddrV6::new( 262 | Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 263 | 32 264 | )) 265 | ); 266 | assert_eq!( 267 | "2a02::1".parse::(), 268 | Ok(BgpAddrV6::new( 269 | Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 1), 270 | 128 271 | )) 272 | ); 273 | } 274 | 275 | #[test] 276 | fn test_ipv6_in_subnet() { 277 | assert!( 278 | BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32) 279 | .in_subnet(&Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 1)) 280 | ); 281 | assert!( 282 | !BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32) 283 | .in_subnet(&Ipv6Addr::new(0x2a01, 0, 0, 0, 0, 0, 0, 1)) 284 | ); 285 | assert!( 286 | BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32).contains( 287 | &BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 33) 288 | ) 289 | ); 290 | } 291 | #[test] 292 | fn test_ipv6_ranges() { 293 | assert_eq!( 294 | BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 120).range_first(), 295 | Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0) 296 | ); 297 | assert_eq!( 298 | BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 120).range_last(), 299 | Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0xff) 300 | ); 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/afi/mac.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module describes NLRI data structures for mac address 10 | 11 | use crate::afi::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// Six-byte ethernet mac address. Used in EVPN. 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | #[serde(transparent)] 20 | pub struct MacAddress { 21 | pub mac_address: [u8; 6], 22 | } 23 | impl MacAddress { 24 | /// Construct new zero mac address. 25 | pub fn new() -> MacAddress { 26 | MacAddress { 27 | mac_address: [0_u8; 6], 28 | } 29 | } 30 | /// Construct new mac address from 6 bytes in network order. 31 | pub fn from_network_bytes(b: &[u8]) -> MacAddress { 32 | MacAddress { 33 | mac_address: [b[5], b[4], b[3], b[2], b[1], b[0]], 34 | } 35 | } 36 | /// Write the mac address to the buffer in network order. 37 | pub fn write_to_network_bytes(&self, b: &mut [u8]) { 38 | let [b0, b1, b2, b3, b4, b5] = self.mac_address; 39 | b.copy_from_slice(&[b5, b4, b3, b2, b1, b0]); 40 | } 41 | /// Construct new mac address from u64. 42 | pub fn from_u64(s: u64) -> MacAddress { 43 | let mut a = [0_u8; 6]; 44 | a[0] = (s & 0xff) as u8; 45 | a[1] = ((s >> 8) & 0xff) as u8; 46 | a[2] = ((s >> 16) & 0xff) as u8; 47 | a[3] = ((s >> 24) & 0xff) as u8; 48 | a[4] = ((s >> 32) & 0xff) as u8; 49 | a[5] = ((s >> 40) & 0xff) as u8; 50 | MacAddress { mac_address: a } 51 | } 52 | /// Pack to u64. 53 | pub fn to_u64(&self) -> u64 { 54 | (self.mac_address[5] as u64) << 40 55 | | (self.mac_address[4] as u64) << 32 56 | | (self.mac_address[3] as u64) << 24 57 | | (self.mac_address[2] as u64) << 16 58 | | (self.mac_address[1] as u64) << 8 59 | | (self.mac_address[0] as u64) 60 | } 61 | } 62 | impl Default for MacAddress { 63 | fn default() -> Self { 64 | Self::new() 65 | } 66 | } 67 | impl std::fmt::Display for MacAddress { 68 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 69 | write!( 70 | f, 71 | "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 72 | self.mac_address[5], 73 | self.mac_address[4], 74 | self.mac_address[3], 75 | self.mac_address[2], 76 | self.mac_address[1], 77 | self.mac_address[0], 78 | ) 79 | } 80 | } 81 | impl std::fmt::Debug for MacAddress { 82 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 83 | f.write_fmt(format_args!( 84 | "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 85 | self.mac_address[5], 86 | self.mac_address[4], 87 | self.mac_address[3], 88 | self.mac_address[2], 89 | self.mac_address[1], 90 | self.mac_address[0] 91 | )) 92 | } 93 | } 94 | impl std::str::FromStr for MacAddress { 95 | type Err = BgpError; 96 | 97 | fn from_str(s: &str) -> Result { 98 | let mut mac: u64 = 0; 99 | let mut cnt: usize = 0; 100 | for c in s.chars() { 101 | if let Some(d) = c.to_digit(16) { 102 | mac = (mac << 4) | (d as u64); 103 | cnt += 1; 104 | } 105 | } 106 | if cnt < 1 { 107 | return Err(BgpError::static_str("Invalid mac address")); 108 | } 109 | Ok(MacAddress::from_u64(mac)) 110 | } 111 | } 112 | /// ipv4 prefix unicast/multicast NLRI 113 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 114 | pub struct BgpAddrMac { 115 | /// mac prefix 116 | pub addr: MacAddress, 117 | /// prefix length 0..48 118 | pub prefixlen: u8, 119 | } 120 | impl BgpAddrMac { 121 | /// Constructs new MAC prefix 122 | /// ``` 123 | /// use zettabgp::afi::mac::MacAddress; 124 | /// use zettabgp::prelude::BgpAddrMac; 125 | /// 126 | /// let pfx = BgpAddrMac::new(MacAddress::from_u64(0x121314151600),40); 127 | /// ``` 128 | pub fn new(address: MacAddress, prefix_len: u8) -> BgpAddrMac { 129 | BgpAddrMac { 130 | addr: address, 131 | prefixlen: prefix_len, 132 | } 133 | } 134 | fn norm_subnet_u48(&self) -> u64 { 135 | self.addr.to_u64() & (((1 << (48 - self.prefixlen)) - 1) ^ 0xffffffffffff) 136 | } 137 | /// Check if mac in subnet 138 | /// ``` 139 | /// use zettabgp::afi::mac::MacAddress; 140 | /// use zettabgp::prelude::BgpAddrMac; 141 | /// 142 | /// assert!(BgpAddrMac::new(MacAddress::from_u64(0x121314151600),40).in_subnet(&MacAddress::from_u64(0x121314151601))) 143 | /// ``` 144 | pub fn in_subnet(&self, a: &MacAddress) -> bool { 145 | if self.prefixlen == 0 { 146 | true 147 | } else if self.prefixlen > 47 { 148 | self.addr.to_u64() == a.to_u64() 149 | } else { 150 | let lv = self.norm_subnet_u48(); 151 | let lh = lv + ((1 << (48 - self.prefixlen)) - 1); 152 | let va = a.to_u64(); 153 | (va >= lv) && (va <= lh) 154 | } 155 | } 156 | /// Returns first mac address (network address) from subnet 157 | /// ``` 158 | /// use zettabgp::afi::mac::MacAddress; 159 | /// use zettabgp::prelude::BgpAddrMac; 160 | /// 161 | /// assert_eq!(BgpAddrMac::new(MacAddress::from_u64(0x1213141516ab),40).range_first() , MacAddress::from_u64(0x121314151600) ); 162 | /// ``` 163 | pub fn range_first(&self) -> MacAddress { 164 | MacAddress::from_u64(self.norm_subnet_u48()) 165 | } 166 | /// Returns last inclusive mac address for subnet 167 | /// ``` 168 | /// use zettabgp::afi::mac::MacAddress; 169 | /// use zettabgp::prelude::BgpAddrMac; 170 | /// 171 | /// assert_eq!(BgpAddrMac::new(MacAddress::from_u64(0x1213141516ab),40).range_last() , MacAddress::from_u64(0x1213141516ff)); 172 | /// ``` 173 | pub fn range_last(&self) -> MacAddress { 174 | if self.prefixlen < 1 { 175 | MacAddress::from_u64(0xffffffffffff) 176 | } else if self.prefixlen > 47 { 177 | self.range_first() 178 | } else { 179 | let lv = self.norm_subnet_u48() + ((1 << (48 - self.prefixlen)) - 1); 180 | MacAddress::from_u64(lv) 181 | } 182 | } 183 | /// Check if given subnet is in this subnet 184 | /// ``` 185 | /// use zettabgp::afi::mac::MacAddress; 186 | /// use zettabgp::prelude::BgpAddrMac; 187 | /// 188 | /// assert!(BgpAddrMac::new(MacAddress::from_u64(0x121314150000),32).contains(&BgpAddrMac::new(MacAddress::from_u64(0x121314151600),40))); 189 | /// ``` 190 | pub fn contains(&self, a: &BgpAddrMac) -> bool { 191 | if self.prefixlen < 1 { 192 | true 193 | } else if self.prefixlen > a.prefixlen { 194 | false 195 | } else if self.prefixlen == a.prefixlen { 196 | self.addr == a.addr 197 | } else { 198 | self.in_subnet(&a.range_first()) && self.in_subnet(&a.range_last()) 199 | } 200 | } 201 | } 202 | impl std::str::FromStr for BgpAddrMac { 203 | type Err = BgpError; 204 | 205 | fn from_str(s: &str) -> Result { 206 | let parts: Vec<&str> = s.split('/').collect(); 207 | if parts.len() < 2 { 208 | Ok(BgpAddrMac { 209 | addr: parts[0].parse::()?, 210 | prefixlen: 48, 211 | }) 212 | } else { 213 | Ok(BgpAddrMac { 214 | addr: parts[0].parse::()?, 215 | prefixlen: parts[1].parse::().unwrap_or(48), 216 | }) 217 | } 218 | } 219 | } 220 | impl std::fmt::Display for BgpAddrMac { 221 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 222 | write!(f, "{}/{}", self.addr, self.prefixlen) 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/afi/mdt.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2022 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module describes NLRI data structures for mdt (multicast distribution tree) safi for ipv4 and ipv6 10 | 11 | use crate::afi::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::default::Default; 15 | use std::net::{Ipv4Addr, Ipv6Addr}; 16 | 17 | /// ipv4 mdt NLRI 18 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 19 | #[cfg(feature = "serialization")] 20 | #[derive(Serialize, Deserialize)] 21 | pub struct BgpMdtV4 { 22 | /// network prefix 23 | pub addr: BgpAddrV4, 24 | /// mdt group 25 | pub group: Ipv4Addr, 26 | } 27 | impl Default for BgpMdtV4 { 28 | fn default() -> Self { 29 | BgpMdtV4 { 30 | addr: BgpAddrV4::default(), 31 | group: Ipv4Addr::new(224, 0, 0, 0), 32 | } 33 | } 34 | } 35 | impl BgpMdtV4 { 36 | /// Constructs new mdtv4 prefix 37 | /// ``` 38 | /// use zettabgp::prelude::{BgpAddrV4,BgpMdtV4}; 39 | /// use std::net::Ipv4Addr; 40 | /// 41 | /// let pfx = BgpMdtV4::new(BgpAddrV4::new(Ipv4Addr::new(192,168,0,0),16),Ipv4Addr::new(224,0,0,0)); 42 | /// ``` 43 | pub fn new(addr: BgpAddrV4, group: Ipv4Addr) -> BgpMdtV4 { 44 | BgpMdtV4 { addr, group } 45 | } 46 | } 47 | impl std::str::FromStr for BgpMdtV4 { 48 | type Err = BgpError; 49 | 50 | fn from_str(s: &str) -> Result { 51 | let addr_grp: Vec<&str> = s.split('@').collect(); 52 | if addr_grp.len() != 2 { 53 | return Err(BgpError::static_str("Invalid MDT")); 54 | }; 55 | Ok(BgpMdtV4 { 56 | addr: addr_grp[0].parse()?, 57 | group: addr_grp[1].parse()?, 58 | }) 59 | } 60 | } 61 | impl BgpItem for BgpMdtV4 { 62 | fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpMdtV4, usize), BgpError> { 63 | if !(32..=128).contains(&bits) { 64 | return Err(BgpError::from_string(format!( 65 | "Invalid BgpMdtV4 FEC length: {:?}", 66 | bits 67 | ))); 68 | } 69 | let mut bf = [0_u8; 4]; 70 | if bits == 32 { 71 | return Ok(( 72 | BgpMdtV4 { 73 | addr: BgpAddrV4 { 74 | addr: decode_addrv4_from(&bf)?, 75 | prefixlen: 0, 76 | }, 77 | group: decode_addrv4_from(buf)?, 78 | }, 79 | 4, 80 | )); 81 | } 82 | let bytes = (((bits - 32) + 7) / 8) as usize; 83 | bf[0..bytes].clone_from_slice(&buf[0..bytes]); 84 | Ok(( 85 | BgpMdtV4 { 86 | addr: BgpAddrV4 { 87 | addr: decode_addrv4_from(&bf)?, 88 | prefixlen: bits - 32, 89 | }, 90 | group: decode_addrv4_from(&buf[bytes..])?, 91 | }, 92 | bytes + 4, 93 | )) 94 | } 95 | fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { 96 | let bytes = if self.addr.prefixlen > 0 { 97 | let mut bf = [0_u8; 4]; 98 | bf.clone_from_slice(&self.addr.addr.octets()); 99 | let bytes = ((self.addr.prefixlen + 7) / 8) as usize; 100 | buf[0..bytes].clone_from_slice(&bf[0..bytes]); 101 | bytes 102 | } else { 103 | 0 104 | }; 105 | buf[bytes..(bytes + 4)].clone_from_slice(&self.group.octets()); 106 | Ok((self.addr.prefixlen + 32, bytes + 4)) 107 | } 108 | fn prefixlen(&self) -> usize { 109 | self.addr.prefixlen as usize 110 | } 111 | } 112 | impl std::fmt::Display for BgpMdtV4 { 113 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 114 | write!(f, "{}@{}", self.addr, self.group) 115 | } 116 | } 117 | 118 | /// ipv6 mdt NLRI 119 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 120 | #[cfg(feature = "serialization")] 121 | #[derive(Serialize, Deserialize)] 122 | pub struct BgpMdtV6 { 123 | /// network prefix 124 | pub addr: BgpAddrV6, 125 | /// mdt group 126 | pub group: Ipv6Addr, 127 | } 128 | impl Default for BgpMdtV6 { 129 | fn default() -> Self { 130 | BgpMdtV6 { 131 | addr: Default::default(), 132 | group: Ipv6Addr::new(0xfe00, 0, 0, 0, 0, 0, 0, 0), 133 | } 134 | } 135 | } 136 | impl BgpMdtV6 { 137 | /// Constructs new mdtv6 prefix 138 | /// ``` 139 | /// use zettabgp::prelude::{BgpAddrV6,BgpMdtV6}; 140 | /// use std::net::Ipv6Addr; 141 | /// 142 | /// let pfx = BgpMdtV6::new(BgpAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1),128),Ipv6Addr::new(0xfe00,0,0,0,0,0,0,0)); 143 | /// ``` 144 | pub fn new(addr: BgpAddrV6, group: Ipv6Addr) -> BgpMdtV6 { 145 | BgpMdtV6 { addr, group } 146 | } 147 | } 148 | impl std::str::FromStr for BgpMdtV6 { 149 | type Err = BgpError; 150 | 151 | fn from_str(s: &str) -> Result { 152 | let addr_grp: Vec<&str> = s.split('@').collect(); 153 | if addr_grp.len() != 2 { 154 | return Err(BgpError::static_str("Invalid MDT")); 155 | }; 156 | Ok(BgpMdtV6 { 157 | addr: addr_grp[0].parse()?, 158 | group: addr_grp[1].parse()?, 159 | }) 160 | } 161 | } 162 | impl BgpItem for BgpMdtV6 { 163 | fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpMdtV6, usize), BgpError> { 164 | if !(128..=254).contains(&bits) { 165 | return Err(BgpError::from_string(format!( 166 | "Invalid BgpMdtV6 FEC length: {:?}", 167 | bits 168 | ))); 169 | } 170 | let mut bf = [0_u8; 16]; 171 | if bits == 128 { 172 | return Ok(( 173 | BgpMdtV6 { 174 | addr: BgpAddrV6 { 175 | addr: decode_addrv6_from(&bf)?, 176 | prefixlen: 0, 177 | }, 178 | group: decode_addrv6_from(buf)?, 179 | }, 180 | 16, 181 | )); 182 | } 183 | let bytes = (((bits - 128) + 7) / 8) as usize; 184 | bf[0..bytes].clone_from_slice(&buf[0..bytes]); 185 | Ok(( 186 | BgpMdtV6 { 187 | addr: BgpAddrV6 { 188 | addr: decode_addrv6_from(&bf)?, 189 | prefixlen: bits - 128, 190 | }, 191 | group: decode_addrv6_from(&buf[bytes..])?, 192 | }, 193 | bytes + 16, 194 | )) 195 | } 196 | fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { 197 | let bytes = if self.addr.prefixlen > 0 { 198 | let mut bf = [0_u8; 16]; 199 | bf.clone_from_slice(&self.addr.addr.octets()); 200 | let bytes = ((self.addr.prefixlen + 7) / 8) as usize; 201 | buf[0..bytes].clone_from_slice(&bf[0..bytes]); 202 | bytes 203 | } else { 204 | 0 205 | }; 206 | buf[bytes..(bytes + 16)].clone_from_slice(&self.group.octets()); 207 | Ok((self.addr.prefixlen + 128, bytes + 16)) 208 | } 209 | fn prefixlen(&self) -> usize { 210 | self.addr.prefixlen as usize 211 | } 212 | } 213 | impl std::fmt::Display for BgpMdtV6 { 214 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 215 | write!(f, "{}@{}", self.addr, self.group) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/afi/mvpn.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module describes NLRI data structures for multicast vpn 10 | 11 | use crate::afi::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP MVPN type 1 - Intra AS I-PMSI AD 16 | /// for example 1:10.255.170.100:1:10.255.170.100 17 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 18 | #[cfg(feature = "serialization")] 19 | #[derive(Serialize, Deserialize)] 20 | pub struct BgpMVPN1 { 21 | pub rd: BgpRD, 22 | pub originator: std::net::IpAddr, 23 | } 24 | impl std::fmt::Display for BgpMVPN1 { 25 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 26 | write!(f, "{}:{}", self.rd, self.originator) 27 | } 28 | } 29 | impl BgpAddrItem for BgpMVPN1 { 30 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN1, usize), BgpError> { 31 | let rdp = BgpRD::decode_from(mode, buf)?; 32 | if mode == BgpTransportMode::IPv4 && buf.len() >= 12 { 33 | return Ok(( 34 | BgpMVPN1 { 35 | rd: rdp.0, 36 | originator: decode_addr_from(&buf[(rdp.1)..(rdp.1 + 4)])?, 37 | }, 38 | rdp.1 + 4, 39 | )); 40 | } 41 | if mode == BgpTransportMode::IPv6 && buf.len() >= 24 { 42 | return Ok(( 43 | BgpMVPN1 { 44 | rd: rdp.0, 45 | originator: decode_addr_from(&buf[(rdp.1)..(rdp.1 + 16)])?, 46 | }, 47 | rdp.1 + 16, 48 | )); 49 | } 50 | Err(BgpError::static_str("Invalid BgpMVPN1 buffer len")) 51 | } 52 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 53 | let p1 = self.rd.encode_to(mode, buf)?; 54 | let p2 = encode_addr_to(&self.originator, &mut buf[p1..])?; 55 | Ok(p1 + p2) 56 | } 57 | } 58 | /// BGP MVPN type 2 - Inter AS I-PMSI AD 59 | /// for example 2:10.255.170.100:1:65000 60 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 61 | #[cfg(feature = "serialization")] 62 | #[derive(Serialize, Deserialize)] 63 | pub struct BgpMVPN2 { 64 | pub rd: BgpRD, 65 | pub asn: u32, 66 | } 67 | impl std::fmt::Display for BgpMVPN2 { 68 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 69 | write!(f, "{}:{}", self.rd, self.asn) 70 | } 71 | } 72 | impl BgpAddrItem for BgpMVPN2 { 73 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN2, usize), BgpError> { 74 | if buf.len() >= 12 { 75 | let rdp = BgpRD::decode_from(mode, buf)?; 76 | return Ok(( 77 | BgpMVPN2 { 78 | rd: rdp.0, 79 | asn: getn_u32(&buf[8..12]), 80 | }, 81 | rdp.1 + 4, 82 | )); 83 | } 84 | Err(BgpError::static_str("Invalid BgpMVPN2 buffer len")) 85 | } 86 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 87 | let p1 = self.rd.encode_to(mode, buf)?; 88 | setn_u32(self.asn, &mut buf[p1..]); 89 | Ok(p1 + 4) 90 | } 91 | } 92 | /// BGP MVPN type 3 - S-PMSI AD 93 | /// for example 3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100 94 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 95 | #[cfg(feature = "serialization")] 96 | #[derive(Serialize, Deserialize)] 97 | pub struct BgpMVPN3 { 98 | pub rd: BgpRD, 99 | pub source: std::net::IpAddr, 100 | pub group: std::net::IpAddr, 101 | pub originator: std::net::IpAddr, 102 | } 103 | impl std::fmt::Display for BgpMVPN3 { 104 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 105 | write!( 106 | f, 107 | "{}:{}:{}:{}", 108 | self.rd, self.source, self.group, self.originator 109 | ) 110 | } 111 | } 112 | impl BgpAddrItem for BgpMVPN3 { 113 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN3, usize), BgpError> { 114 | let rdp = BgpRD::decode_from(mode, buf)?; 115 | if mode == BgpTransportMode::IPv4 && buf.len() >= 22 { 116 | if buf[8] != 32 || buf[13] != 32 { 117 | return Err(BgpError::from_string(format!( 118 | "Invalid BgpMVPN3 v4 prefix len: {:?}", 119 | buf 120 | ))); 121 | } 122 | return Ok(( 123 | BgpMVPN3 { 124 | rd: rdp.0, 125 | source: decode_addr_from(&buf[9..13])?, 126 | group: decode_addr_from(&buf[14..18])?, 127 | originator: decode_addr_from(&buf[18..22])?, 128 | }, 129 | 22, 130 | )); 131 | } 132 | if mode == BgpTransportMode::IPv6 && buf.len() >= 58 { 133 | if buf[8] != 128 || buf[25] != 128 { 134 | return Err(BgpError::static_str("Invalid BgpMVPN3 v6 prefix len")); 135 | } 136 | return Ok(( 137 | BgpMVPN3 { 138 | rd: rdp.0, 139 | source: decode_addr_from(&buf[9..25])?, 140 | group: decode_addr_from(&buf[26..42])?, 141 | originator: decode_addr_from(&buf[42..58])?, 142 | }, 143 | 58, 144 | )); 145 | } 146 | Err(BgpError::static_str("Invalid BgpMVPN3 buffer len")) 147 | } 148 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 149 | let mut p1 = self.rd.encode_to(mode, buf)?; 150 | p1 += encode_addr_to(&self.source, &mut buf[p1..])?; 151 | p1 += encode_addr_to(&self.group, &mut buf[p1..])?; 152 | p1 += encode_addr_to(&self.originator, &mut buf[p1..])?; 153 | Ok(p1) 154 | } 155 | } 156 | /// BGP MVPN type 4 - Leaf AD 157 | /// for example 4:3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100:10.255.170.98 158 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 159 | #[cfg(feature = "serialization")] 160 | #[derive(Serialize, Deserialize)] 161 | pub struct BgpMVPN4 { 162 | pub spmsi: BgpMVPN3, 163 | pub originator: std::net::IpAddr, 164 | } 165 | impl std::fmt::Display for BgpMVPN4 { 166 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 167 | write!(f, "{}:{}", self.spmsi, self.originator) 168 | } 169 | } 170 | impl BgpAddrItem for BgpMVPN4 { 171 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN4, usize), BgpError> { 172 | if buf[0] != 3 || buf[1] != 22 { 173 | return Err(BgpError::from_string(format!( 174 | "BgpMVPN4 decode error: {:?}", 175 | buf 176 | ))); 177 | } 178 | match BgpMVPN3::decode_from(mode, &buf[2..]) { 179 | Err(e) => Err(BgpError::from_string(format!( 180 | "BgpMVPN4 decode error for MVPNV3: {}, buf: {:?}", 181 | e, buf 182 | ))), 183 | Ok(s) => Ok(( 184 | BgpMVPN4 { 185 | spmsi: s.0, 186 | originator: decode_addr_from(&buf[(2 + s.1)..])?, 187 | }, 188 | s.1 + 6, 189 | )), 190 | } 191 | } 192 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 193 | let mut p1 = self.spmsi.encode_to(mode, buf)?; 194 | p1 += encode_addr_to(&self.originator, &mut buf[p1..])?; 195 | Ok(p1) 196 | } 197 | } 198 | /// BGP MVPN type 5 - Source Active AD 199 | /// for example 5:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3 200 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 201 | #[cfg(feature = "serialization")] 202 | #[derive(Serialize, Deserialize)] 203 | pub struct BgpMVPN5 { 204 | pub rd: BgpRD, 205 | pub source: std::net::IpAddr, 206 | pub group: std::net::IpAddr, 207 | } 208 | impl std::fmt::Display for BgpMVPN5 { 209 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 210 | write!(f, "{}:{}:{}", self.rd, self.source, self.group) 211 | } 212 | } 213 | impl BgpAddrItem for BgpMVPN5 { 214 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN5, usize), BgpError> { 215 | let rdp = BgpRD::decode_from(mode, buf)?; 216 | if mode == BgpTransportMode::IPv4 && buf.len() >= 18 { 217 | if buf[8] != 32 || buf[13] != 32 { 218 | return Err(BgpError::static_str("Invalid BgpMVPN3 v4 prefix len")); 219 | } 220 | return Ok(( 221 | BgpMVPN5 { 222 | rd: rdp.0, 223 | source: decode_addr_from(&buf[9..13])?, 224 | group: decode_addr_from(&buf[14..18])?, 225 | }, 226 | 18, 227 | )); 228 | } 229 | if mode == BgpTransportMode::IPv6 && buf.len() >= 42 { 230 | if buf[8] != 128 || buf[25] != 128 { 231 | return Err(BgpError::static_str("Invalid BgpMVPN3 v6 prefix len")); 232 | } 233 | return Ok(( 234 | BgpMVPN5 { 235 | rd: rdp.0, 236 | source: decode_addr_from(&buf[9..15])?, 237 | group: decode_addr_from(&buf[26..42])?, 238 | }, 239 | 42, 240 | )); 241 | } 242 | Err(BgpError::static_str("Invalid BgpMVPN5 buffer len")) 243 | } 244 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 245 | let mut p1 = self.rd.encode_to(mode, buf)?; 246 | p1 += encode_addr_to(&self.source, &mut buf[p1..])?; 247 | p1 += encode_addr_to(&self.group, &mut buf[p1..])?; 248 | Ok(p1) 249 | } 250 | } 251 | /// BGP MVPN type 6 - Shared Tree Join or type 7 - Source Tree Join 252 | /// for example 6:10.255.170.100:1:65000:32:10.12.53.12:32:224.1.2.3 253 | /// 7:10.255.170.100:1:65000:32:192.168.194.2:32:224.1.2.3 254 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 255 | #[cfg(feature = "serialization")] 256 | #[derive(Serialize, Deserialize)] 257 | pub struct BgpMVPN67 { 258 | pub rd: BgpRD, 259 | pub asn: u32, 260 | pub rp: std::net::IpAddr, 261 | pub group: std::net::IpAddr, 262 | } 263 | impl std::fmt::Display for BgpMVPN67 { 264 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 265 | write!(f, "{}:{}:{}:{}", self.rd, self.asn, self.rp, self.group) 266 | } 267 | } 268 | impl BgpAddrItem for BgpMVPN67 { 269 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN67, usize), BgpError> { 270 | let rdp = BgpRD::decode_from(mode, buf)?; 271 | if mode == BgpTransportMode::IPv4 && buf.len() >= 22 { 272 | if buf[12] != 32 || buf[17] != 32 { 273 | return Err(BgpError::static_str("Invalid BgpMVPN67 v4 prefix len")); 274 | } 275 | return Ok(( 276 | BgpMVPN67 { 277 | rd: rdp.0, 278 | asn: getn_u32(&buf[8..12]), 279 | rp: decode_addr_from(&buf[13..17])?, 280 | group: decode_addr_from(&buf[18..22])?, 281 | }, 282 | 22, 283 | )); 284 | } 285 | if mode == BgpTransportMode::IPv6 && buf.len() >= 46 { 286 | if buf[12] != 128 || buf[29] != 128 { 287 | return Err(BgpError::static_str("Invalid BgpMVPN67 v6 prefix len")); 288 | } 289 | return Ok(( 290 | BgpMVPN67 { 291 | rd: rdp.0, 292 | asn: getn_u32(&buf[8..12]), 293 | rp: decode_addr_from(&buf[13..29])?, 294 | group: decode_addr_from(&buf[30..46])?, 295 | }, 296 | 46, 297 | )); 298 | } 299 | Err(BgpError::static_str("Invalid BgpMVPN67 buffer len")) 300 | } 301 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 302 | let mut p1 = self.rd.encode_to(mode, buf)?; 303 | setn_u32(self.asn, &mut buf[p1..]); 304 | p1 += 4; 305 | p1 += encode_addr_to(&self.rp, &mut buf[p1..])?; 306 | p1 += encode_addr_to(&self.group, &mut buf[p1..])?; 307 | Ok(p1) 308 | } 309 | } 310 | // BGP Multicast VPN NLRI 311 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 312 | #[cfg(feature = "serialization")] 313 | #[derive(Serialize, Deserialize)] 314 | pub enum BgpMVPN { 315 | T1(BgpMVPN1), //Intra AS I-PMSI AD 1:10.255.170.100:1:10.255.170.100 316 | T2(BgpMVPN2), //Inter AS I-PMSI AD 2:10.255.170.100:1:65000 317 | T3(BgpMVPN3), //S-PMSI AD 3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100 318 | T4(BgpMVPN4), //Leaf AD 4:3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100:10.255.170.98 319 | T5(BgpMVPN5), //Source Active AD 5:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3 320 | T6(BgpMVPN67), //Shared Tree Join 6:10.255.170.100:1:65000:32:10.12.53.12:32:224.1.2.3 321 | T7(BgpMVPN67), //Source Tree Join 7:10.255.170.100:1:65000:32:192.168.194.2:32:224.1.2.3 322 | } 323 | impl std::fmt::Display for BgpMVPN { 324 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 325 | match self { 326 | BgpMVPN::T1(s) => write!(f, "1:{}", s), 327 | BgpMVPN::T2(s) => write!(f, "2:{}", s), 328 | BgpMVPN::T3(s) => write!(f, "3:{}", s), 329 | BgpMVPN::T4(s) => write!(f, "4:{}", s), 330 | BgpMVPN::T5(s) => write!(f, "5:{}", s), 331 | BgpMVPN::T6(s) => write!(f, "6:{}", s), 332 | BgpMVPN::T7(s) => write!(f, "7:{}", s), 333 | } 334 | } 335 | } 336 | impl BgpAddrItem for BgpMVPN { 337 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpMVPN, usize), BgpError> { 338 | let mvpntype = buf[0]; 339 | let routelen = buf[1] as usize; 340 | match mvpntype { 341 | 1 => { 342 | let r = BgpMVPN1::decode_from(mode, &buf[2..(2 + routelen)])?; 343 | Ok((BgpMVPN::T1(r.0), r.1 + 2)) 344 | } 345 | 2 => { 346 | let r = BgpMVPN2::decode_from(mode, &buf[2..(2 + routelen)])?; 347 | Ok((BgpMVPN::T2(r.0), r.1 + 2)) 348 | } 349 | 3 => { 350 | let r = BgpMVPN3::decode_from(mode, &buf[2..(2 + routelen)])?; 351 | Ok((BgpMVPN::T3(r.0), r.1 + 2)) 352 | } 353 | 4 => { 354 | let r = BgpMVPN4::decode_from(mode, &buf[2..(2 + routelen)])?; 355 | Ok((BgpMVPN::T4(r.0), r.1 + 2)) 356 | } 357 | 5 => { 358 | let r = BgpMVPN5::decode_from(mode, &buf[2..(2 + routelen)])?; 359 | Ok((BgpMVPN::T5(r.0), r.1 + 2)) 360 | } 361 | 6 => { 362 | let r = BgpMVPN67::decode_from(mode, &buf[2..(2 + routelen)])?; 363 | Ok((BgpMVPN::T6(r.0), r.1 + 2)) 364 | } 365 | 7 => { 366 | let r = BgpMVPN67::decode_from(mode, &buf[2..(2 + routelen)])?; 367 | Ok((BgpMVPN::T7(r.0), r.1 + 2)) 368 | } 369 | _ => Err(BgpError::from_string(format!( 370 | "Invalid BgpMVPN route type: {:?}", 371 | buf 372 | ))), 373 | } 374 | } 375 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 376 | let sz = match self { 377 | BgpMVPN::T1(r) => { 378 | buf[0] = 1; 379 | r.encode_to(mode, &mut buf[2..])? 380 | } 381 | BgpMVPN::T2(r) => { 382 | buf[0] = 2; 383 | r.encode_to(mode, &mut buf[2..])? 384 | } 385 | BgpMVPN::T3(r) => { 386 | buf[0] = 3; 387 | r.encode_to(mode, &mut buf[2..])? 388 | } 389 | BgpMVPN::T4(r) => { 390 | buf[0] = 4; 391 | r.encode_to(mode, &mut buf[2..])? 392 | } 393 | BgpMVPN::T5(r) => { 394 | buf[0] = 5; 395 | r.encode_to(mode, &mut buf[2..])? 396 | } 397 | BgpMVPN::T6(r) => { 398 | buf[0] = 6; 399 | r.encode_to(mode, &mut buf[2..])? 400 | } 401 | BgpMVPN::T7(r) => { 402 | buf[0] = 7; 403 | r.encode_to(mode, &mut buf[2..])? 404 | } 405 | }; 406 | buf[1] = sz as u8; 407 | Ok(sz + 2) 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /src/afi/vpls.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module describes NLRI data structures for vpls 10 | 11 | use crate::afi::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP VPLS NLRI 16 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub struct BgpAddrL2 { 20 | pub rd: BgpRD, 21 | pub site: u16, 22 | pub offset: u16, 23 | pub range: u16, 24 | pub labels: MplsLabels, 25 | } 26 | impl BgpItemLong for BgpAddrL2 { 27 | fn extract_from(size: usize, buf: &[u8]) -> Result { 28 | if size < 17 { 29 | return Err(BgpError::from_string(format!( 30 | "Invalid FEC length for BgpAddrL2: {:?} bytes", 31 | size 32 | ))); 33 | } 34 | let srd = BgpRD::decode_from(BgpTransportMode::IPv4, buf)?; 35 | let lbls = MplsLabels::extract_bits_from(((size - 14) * 8) as u8, &buf[14..])?; 36 | Ok(BgpAddrL2 { 37 | rd: srd.0, 38 | site: getn_u16(&buf[8..10]), 39 | offset: getn_u16(&buf[10..12]), 40 | range: getn_u16(&buf[12..14]), 41 | labels: lbls.0, 42 | }) 43 | } 44 | fn pack_to(&self, buf: &mut [u8]) -> Result { 45 | if buf.len() < 15 { 46 | return Err(BgpError::insufficient_buffer_size()); 47 | } 48 | self.rd.encode_rd_to(buf)?; 49 | setn_u16(self.site, &mut buf[8..10]); 50 | setn_u16(self.offset, &mut buf[10..12]); 51 | setn_u16(self.range, &mut buf[12..14]); 52 | let r = self.labels.set_bits_to(&mut buf[14..])?; 53 | Ok(r.1 + 14) 54 | } 55 | } 56 | impl std::fmt::Display for BgpAddrL2 { 57 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 58 | write!( 59 | f, 60 | "<{}> {}::{}..{}", 61 | self.rd, self.site, self.offset, self.range 62 | ) 63 | } 64 | } 65 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 66 | #[cfg(feature = "serialization")] 67 | #[derive(Serialize, Deserialize)] 68 | pub struct BgpL2 { 69 | pub rd: BgpRD, 70 | pub site: u16, 71 | pub offset: u16, 72 | pub range: u16, 73 | } 74 | impl BgpL2 { 75 | pub fn new(srd: BgpRD, st: u16, ofs: u16, rng: u16) -> BgpL2 { 76 | BgpL2 { 77 | rd: srd, 78 | site: st, 79 | offset: ofs, 80 | range: rng, 81 | } 82 | } 83 | } 84 | impl std::fmt::Display for BgpL2 { 85 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 86 | write!( 87 | f, 88 | "<{}>site {}-{}..{}", 89 | self.rd, self.site, self.offset, self.range 90 | ) 91 | } 92 | } 93 | impl BgpAddrItem for BgpL2 { 94 | fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpL2, usize), BgpError> { 95 | if buf.len() >= 14 { 96 | let rdp = BgpRD::decode_from(mode, &buf[0..8])?; 97 | Ok(( 98 | BgpL2 { 99 | rd: rdp.0, 100 | site: getn_u16(&buf[8..10]), 101 | offset: getn_u16(&buf[10..12]), 102 | range: getn_u16(&buf[12..14]), 103 | }, 104 | 14, 105 | )) 106 | } else { 107 | Err(BgpError::static_str("Invalid BgpL2 buffer len")) 108 | } 109 | } 110 | fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result { 111 | let pos = self.rd.encode_to(mode, buf)?; 112 | setn_u16(self.site, &mut buf[pos..]); 113 | setn_u16(self.offset, &mut buf[pos + 2..]); 114 | setn_u16(self.range, &mut buf[pos + 4..]); 115 | Ok(pos + 6) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/bmp/bmputl.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Some BMP utilities 10 | 11 | use crate::afi::*; 12 | use crate::*; 13 | use std::cmp::Ordering; 14 | 15 | pub fn decode_bmp_addr_from(buf: &[u8]) -> Result { 16 | if buf.len() < 16 { 17 | return Err(BgpError::insufficient_buffer_size()); 18 | } 19 | if buf[0] == 0 20 | && buf[1] == 0 21 | && buf[2] == 0 22 | && buf[3] == 0 23 | && buf[4] == 0 24 | && buf[5] == 0 25 | && buf[6] == 0 26 | && buf[7] == 0 27 | && buf[8] == 0 28 | && buf[9] == 0 29 | && buf[10] == 0 30 | && buf[11] == 0 31 | { 32 | Ok(std::net::IpAddr::V4(decode_addrv4_from(&buf[12..])?)) 33 | } else { 34 | Ok(std::net::IpAddr::V6(decode_addrv6_from(buf)?)) 35 | } 36 | } 37 | pub fn encode_bmp_addr_to(addr: &std::net::IpAddr, buf: &mut [u8]) -> Result { 38 | if buf.len() < 16 { 39 | return Err(BgpError::insufficient_buffer_size()); 40 | } 41 | match addr { 42 | std::net::IpAddr::V4(v4) => { 43 | for byte in buf.iter_mut() { 44 | *byte = 0; 45 | } 46 | encode_addrv4_to(v4, &mut buf[12..])?; 47 | } 48 | std::net::IpAddr::V6(v6) => { 49 | encode_addrv6_to(v6, buf)?; 50 | } 51 | } 52 | Ok(16) 53 | } 54 | 55 | /// peer header 56 | #[derive(Debug, Clone)] 57 | pub struct BmpMessagePeerHeader { 58 | /// peer type code 59 | pub peertype: u8, 60 | /// flags 61 | pub flags: u8, 62 | /// route distinguisher of VRF of this peer 63 | pub peerdistinguisher: BgpRD, 64 | /// peer IP address 65 | pub peeraddress: std::net::IpAddr, 66 | /// peer AS number 67 | pub asnum: u32, 68 | /// peer router ID 69 | pub routerid: std::net::Ipv4Addr, 70 | /// timestamp 71 | pub timestamp: u64, 72 | } 73 | 74 | impl BmpMessagePeerHeader { 75 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessagePeerHeader, usize), BgpError> { 76 | if buf.len() < 42 { 77 | return Err(BgpError::InsufficientBufferSize); 78 | } 79 | Ok(( 80 | BmpMessagePeerHeader { 81 | peertype: buf[0], 82 | flags: buf[1], 83 | peerdistinguisher: BgpRD::decode_from(BgpTransportMode::IPv4, &buf[2..])?.0, 84 | peeraddress: decode_bmp_addr_from(&buf[10..])?, 85 | asnum: getn_u32(&buf[26..]), 86 | routerid: decode_addrv4_from(&buf[30..])?, 87 | timestamp: getn_u64(&buf[34..]), 88 | }, 89 | 42, 90 | )) 91 | } 92 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 93 | if buf.len() < 42 { 94 | return Err(BgpError::InsufficientBufferSize); 95 | } 96 | buf[0] = self.peertype; 97 | buf[1] = self.flags; 98 | self.peerdistinguisher 99 | .encode_to(BgpTransportMode::IPv4, &mut buf[2..])?; 100 | encode_bmp_addr_to(&self.peeraddress, &mut buf[10..])?; 101 | setn_u32(self.asnum, &mut buf[26..]); 102 | encode_addrv4_to(&self.routerid, &mut buf[30..])?; 103 | setn_u64(self.timestamp, &mut buf[34..]); 104 | Ok(42) 105 | } 106 | } 107 | impl PartialOrd for BmpMessagePeerHeader { 108 | fn partial_cmp(&self, other: &Self) -> Option { 109 | if let Some(pc) = self.peertype.partial_cmp(&other.peertype) { 110 | match pc { 111 | Ordering::Less => return Some(Ordering::Less), 112 | Ordering::Greater => return Some(Ordering::Greater), 113 | Ordering::Equal => {} 114 | } 115 | }; 116 | if let Some(pc) = self.flags.partial_cmp(&other.flags) { 117 | match pc { 118 | Ordering::Less => return Some(Ordering::Less), 119 | Ordering::Greater => return Some(Ordering::Greater), 120 | Ordering::Equal => {} 121 | } 122 | }; 123 | if let Some(pc) = self.peerdistinguisher.partial_cmp(&other.peerdistinguisher) { 124 | match pc { 125 | Ordering::Less => return Some(Ordering::Less), 126 | Ordering::Greater => return Some(Ordering::Greater), 127 | Ordering::Equal => {} 128 | } 129 | }; 130 | if let Some(pc) = self.peeraddress.partial_cmp(&other.peeraddress) { 131 | match pc { 132 | Ordering::Less => return Some(Ordering::Less), 133 | Ordering::Greater => return Some(Ordering::Greater), 134 | Ordering::Equal => {} 135 | } 136 | }; 137 | if let Some(pc) = self.asnum.partial_cmp(&other.asnum) { 138 | match pc { 139 | Ordering::Less => return Some(Ordering::Less), 140 | Ordering::Greater => return Some(Ordering::Greater), 141 | Ordering::Equal => {} 142 | } 143 | }; 144 | self.routerid.partial_cmp(&other.routerid) 145 | } 146 | } 147 | impl Ord for BmpMessagePeerHeader { 148 | fn cmp(&self, other: &Self) -> Ordering { 149 | match self.peertype.cmp(&other.peertype) { 150 | Ordering::Equal => {} 151 | x => return x, 152 | }; 153 | match self.flags.cmp(&other.flags) { 154 | Ordering::Equal => {} 155 | x => return x, 156 | }; 157 | match self.peerdistinguisher.cmp(&other.peerdistinguisher) { 158 | Ordering::Equal => {} 159 | x => return x, 160 | }; 161 | match self.peeraddress.cmp(&other.peeraddress) { 162 | Ordering::Equal => {} 163 | x => return x, 164 | }; 165 | match self.asnum.cmp(&other.asnum) { 166 | Ordering::Equal => {} 167 | x => return x, 168 | }; 169 | self.routerid.cmp(&other.routerid) 170 | } 171 | } 172 | 173 | impl PartialEq for BmpMessagePeerHeader { 174 | fn eq(&self, other: &Self) -> bool { 175 | self.peertype == other.peertype 176 | && self.flags == other.flags 177 | && self.peerdistinguisher == other.peerdistinguisher 178 | && self.peeraddress == other.peeraddress 179 | && self.asnum == other.asnum 180 | && self.routerid == other.routerid 181 | } 182 | } 183 | impl Eq for BmpMessagePeerHeader {} 184 | impl From<&BmpMessagePeerHeader> for BgpSessionParams { 185 | #[inline] 186 | fn from(bmph: &BmpMessagePeerHeader) -> BgpSessionParams { 187 | BgpSessionParams::new( 188 | bmph.asnum, 189 | 0, 190 | bmph.peeraddress.into(), 191 | bmph.routerid, 192 | Vec::new(), 193 | ) 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/bmp/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP Monitoring Protocol (BMP) processing - 10 | 11 | mod bmputl; 12 | mod msginit; 13 | mod msgpeer; 14 | mod msgrmon; 15 | mod msgterm; 16 | pub mod prelude; 17 | 18 | use crate::prelude::*; 19 | use bmputl::*; 20 | use msginit::BmpMessageInitiation; 21 | use msgpeer::{BmpMessagePeerDown, BmpMessagePeerUp}; 22 | use msgrmon::BmpMessageRouteMonitoring; 23 | use msgterm::BmpMessageTermination; 24 | use std::collections::BTreeMap; 25 | 26 | ///BGP session key 27 | #[derive(Debug, PartialEq, PartialOrd, Eq, Ord)] 28 | pub struct BgpSessionKey { 29 | pub peer_rd: BgpRD, 30 | pub peer_ip: std::net::IpAddr, 31 | } 32 | impl BgpSessionKey { 33 | pub fn new(peer_rd: BgpRD, peer_ip: std::net::IpAddr) -> BgpSessionKey { 34 | BgpSessionKey { peer_rd, peer_ip } 35 | } 36 | } 37 | impl From<&BmpMessagePeerHeader> for BgpSessionKey { 38 | fn from(peer: &BmpMessagePeerHeader) -> BgpSessionKey { 39 | BgpSessionKey { 40 | peer_rd: peer.peerdistinguisher.clone(), 41 | peer_ip: peer.peeraddress, 42 | } 43 | } 44 | } 45 | ///BMP Session 46 | #[derive(Default)] 47 | pub struct BMPSession { 48 | pub sessions: BTreeMap, 49 | } 50 | impl BMPSession { 51 | pub fn decode_from(&mut self, buf: &[u8]) -> Result { 52 | let msgtype = buf[0]; 53 | match msgtype { 54 | 0 => { 55 | let rm = self.decode_rm(&buf[1..])?; 56 | Ok(BmpMessage::RouteMonitoring(rm)) 57 | } 58 | 1 => Ok(BmpMessage::StatisticsReport), 59 | 2 => { 60 | let peerdown = BmpMessagePeerDown::decode_from(&buf[1..])?.0; 61 | self.sessions.remove(&BgpSessionKey::from(&peerdown.peer)); 62 | Ok(BmpMessage::PeerDownNotification(peerdown)) 63 | } 64 | 3 => { 65 | let peerup = BmpMessagePeerUp::decode_from(&buf[1..])?.0; 66 | self.sessions 67 | .insert(BgpSessionKey::from(&peerup.peer), peerup.clone()); 68 | Ok(BmpMessage::PeerUpNotification(peerup)) 69 | } 70 | 4 => Ok(BmpMessage::Initiation( 71 | BmpMessageInitiation::decode_from(&buf[1..])?.0, 72 | )), 73 | 5 => Ok(BmpMessage::Termination( 74 | BmpMessageTermination::decode_from(&buf[1..])?.0, 75 | )), 76 | 6 => Ok(BmpMessage::RouteMirroring), 77 | _ => Err(BgpError::static_str("Invalid BMP message type")), 78 | } 79 | } 80 | fn decode_rm(&self, buf: &[u8]) -> Result { 81 | if buf.len() < 62 { 82 | return Err(BgpError::InsufficientBufferSize); 83 | } 84 | let pm = BmpMessagePeerHeader::decode_from(buf)?; 85 | let mut pos = pm.1; 86 | let sesskey = BgpSessionKey::from(&pm.0); 87 | let sesspars: BgpSessionParams = match self.sessions.get(&sesskey) { 88 | None => (&pm.0).into(), 89 | Some(peer) => { 90 | if peer.peer.routerid == peer.msg1.router_id { 91 | BgpSessionParams::from(&peer.msg1) 92 | } else { 93 | BgpSessionParams::from(&peer.msg2) 94 | } 95 | } 96 | }; 97 | let msgt = sesspars.decode_message_head(&buf[pos..])?; 98 | pos += 19; 99 | if msgt.0 != BgpMessageType::Update { 100 | return Err(BgpError::static_str( 101 | "Invalid BGP message type for BmpMessageRouteMonitoring", 102 | )); 103 | } 104 | let mut upd = BgpUpdateMessage::new(); 105 | upd.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; 106 | //pos += msgt.1; 107 | Ok(BmpMessageRouteMonitoring { 108 | peer: pm.0, 109 | update: upd, 110 | }) 111 | } 112 | } 113 | /// BMP message 114 | #[derive(Debug)] 115 | pub enum BmpMessage { 116 | RouteMonitoring(BmpMessageRouteMonitoring), //0 117 | StatisticsReport, //1 118 | PeerDownNotification(BmpMessagePeerDown), //2 119 | PeerUpNotification(BmpMessagePeerUp), //3 120 | Initiation(BmpMessageInitiation), //4 121 | Termination(BmpMessageTermination), //5 122 | RouteMirroring, //6 123 | } 124 | 125 | /// BMP message header 126 | #[derive(Debug)] 127 | pub struct BmpMessageHeader { 128 | /// version - always 3 129 | pub version: u8, 130 | /// total message length in bytes 131 | pub msglength: usize, 132 | } 133 | 134 | impl BmpMessageHeader { 135 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageHeader, usize), BgpError> { 136 | if buf.len() < 5 { 137 | return Err(BgpError::insufficient_buffer_size()); 138 | } 139 | if buf[0] != 3 { 140 | return Err(BgpError::static_str("BMP packet version != 3")); 141 | } 142 | Ok(( 143 | BmpMessageHeader { 144 | version: buf[0], 145 | msglength: getn_u32(&buf[1..5]) as usize, 146 | }, 147 | 5, 148 | )) 149 | } 150 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 151 | if buf.len() < 5 { 152 | return Err(BgpError::insufficient_buffer_size()); 153 | } 154 | buf[0] = self.version; 155 | setn_u32(self.msglength as u32, &mut buf[1..]); 156 | Ok(5) 157 | } 158 | } 159 | 160 | impl BmpMessage { 161 | pub fn decode_from(buf: &[u8]) -> Result { 162 | let msgtype = buf[0]; 163 | match msgtype { 164 | 0 => Ok(BmpMessage::RouteMonitoring( 165 | BmpMessageRouteMonitoring::decode_from(&buf[1..])?.0, 166 | )), 167 | 1 => Ok(BmpMessage::StatisticsReport), 168 | 2 => Ok(BmpMessage::PeerDownNotification( 169 | BmpMessagePeerDown::decode_from(&buf[1..])?.0, 170 | )), 171 | 3 => Ok(BmpMessage::PeerUpNotification( 172 | BmpMessagePeerUp::decode_from(&buf[1..])?.0, 173 | )), 174 | 4 => Ok(BmpMessage::Initiation( 175 | BmpMessageInitiation::decode_from(&buf[1..])?.0, 176 | )), 177 | 5 => Ok(BmpMessage::Termination( 178 | BmpMessageTermination::decode_from(&buf[1..])?.0, 179 | )), 180 | 6 => Ok(BmpMessage::RouteMirroring), 181 | _ => Err(BgpError::static_str("Invalid BMP message type")), 182 | } 183 | } 184 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 185 | if buf.is_empty() { 186 | return Err(BgpError::insufficient_buffer_size()); 187 | } 188 | let mut curpos = 0; 189 | match self { 190 | BmpMessage::RouteMonitoring(rm) => { 191 | buf[0] = 0; 192 | curpos += 1; 193 | curpos += rm.encode_to(&mut buf[1..])?; 194 | } 195 | BmpMessage::StatisticsReport => { 196 | unimplemented!() 197 | } 198 | BmpMessage::PeerDownNotification(peerdown) => { 199 | buf[0] = 2; 200 | curpos += 1; 201 | curpos += peerdown.encode_to(&mut buf[1..])?; 202 | } 203 | BmpMessage::PeerUpNotification(peerup) => { 204 | buf[0] = 3; 205 | curpos += 1; 206 | curpos += peerup.encode_to(&mut buf[1..])?; 207 | } 208 | BmpMessage::Initiation(init) => { 209 | buf[0] = 4; 210 | curpos += 1; 211 | curpos += init.encode_to(&mut buf[1..])?; 212 | } 213 | BmpMessage::Termination(term) => { 214 | buf[0] = 5; 215 | curpos += 1; 216 | curpos += term.encode_to(&mut buf[1..])?; 217 | } 218 | BmpMessage::RouteMirroring => { 219 | unimplemented!() 220 | } 221 | } 222 | Ok(curpos) 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/bmp/msginit.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BMP init message 10 | 11 | use crate::*; 12 | 13 | /// information value 14 | pub struct BmpInfoVal { 15 | /// information type 16 | pub infotype: u16, 17 | /// information string 18 | pub info: String, 19 | } 20 | 21 | impl BmpInfoVal { 22 | fn decode_from(buf: &[u8]) -> Result<(BmpInfoVal, usize), BgpError> { 23 | if buf.len() < 4 { 24 | return Err(BgpError::insufficient_buffer_size()); 25 | }; 26 | let tp = getn_u16(buf); 27 | let ln = getn_u16(&buf[2..4]) as usize; 28 | if ln > (buf.len() - 4) { 29 | return Err(BgpError::insufficient_buffer_size()); 30 | }; 31 | Ok(( 32 | BmpInfoVal { 33 | infotype: tp, 34 | info: core::str::from_utf8(&buf[4..4 + ln])?.to_string(), 35 | }, 36 | ln + 4, 37 | )) 38 | } 39 | fn encode_to(&self, buf: &mut [u8]) -> Result { 40 | if buf.len() < 4 { 41 | return Err(BgpError::insufficient_buffer_size()); 42 | }; 43 | let mut curpos = 0; 44 | setn_u16(self.infotype, &mut buf[curpos..]); 45 | curpos += 2; 46 | let info = self.info.as_bytes(); 47 | setn_u16(info.len() as u16, &mut buf[curpos..]); 48 | curpos += 2; 49 | buf[curpos..curpos + info.len()].copy_from_slice(info); 50 | curpos += info.len(); 51 | Ok(curpos) 52 | } 53 | } 54 | 55 | /// BMP init message 56 | #[derive(Debug, Clone, PartialEq, Eq)] 57 | pub struct BmpMessageInitiation { 58 | /// string 59 | pub str0: Option, 60 | /// system description 61 | pub sys_descr: Option, 62 | /// system name 63 | pub sys_name: Option, 64 | } 65 | 66 | impl BmpMessageInitiation { 67 | pub fn new() -> BmpMessageInitiation { 68 | BmpMessageInitiation { 69 | str0: None, 70 | sys_descr: None, 71 | sys_name: None, 72 | } 73 | } 74 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageInitiation, usize), BgpError> { 75 | let mut pos: usize = 0; 76 | let mut ret: BmpMessageInitiation = BmpMessageInitiation::new(); 77 | while pos < buf.len() { 78 | let c = BmpInfoVal::decode_from(&buf[pos..])?; 79 | match c.0.infotype { 80 | 0 => ret.str0 = Some(c.0.info), 81 | 1 => ret.sys_descr = Some(c.0.info), 82 | 2 => ret.sys_name = Some(c.0.info), 83 | _ => {} 84 | }; 85 | pos += c.1; 86 | } 87 | Ok((ret, pos)) 88 | } 89 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 90 | let mut curpos: usize = 0; 91 | if let Some(str0) = &self.str0 { 92 | curpos += (BmpInfoVal { 93 | infotype: 0, 94 | info: str0.clone(), 95 | }) 96 | .encode_to(&mut buf[curpos..])?; 97 | } 98 | if let Some(sys_descr) = &self.sys_descr { 99 | curpos += (BmpInfoVal { 100 | infotype: 0, 101 | info: sys_descr.clone(), 102 | }) 103 | .encode_to(&mut buf[curpos..])?; 104 | } 105 | if let Some(sys_name) = &self.sys_name { 106 | curpos += (BmpInfoVal { 107 | infotype: 0, 108 | info: sys_name.to_string(), 109 | }) 110 | .encode_to(&mut buf[curpos..])?; 111 | } 112 | Ok(curpos) 113 | } 114 | } 115 | impl Default for BmpMessageInitiation { 116 | fn default() -> Self { 117 | Self::new() 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/bmp/msgpeer.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::bmp::bmputl::*; 10 | use crate::message::notification::BgpNotificationMessage; 11 | use crate::message::open::BgpOpenMessage; 12 | use crate::message::*; 13 | use crate::util::*; 14 | use crate::{BgpError, BgpMessage, BgpSessionParams}; 15 | 16 | use std::convert::TryInto; 17 | 18 | #[derive(Debug, Clone)] 19 | pub struct BmpMessagePeerUp { 20 | pub peer: BmpMessagePeerHeader, 21 | pub localaddress: std::net::IpAddr, 22 | pub localport: u16, 23 | pub remoteport: u16, 24 | pub msg1: BgpOpenMessage, 25 | pub msg2: BgpOpenMessage, 26 | } 27 | 28 | #[derive(Debug)] 29 | pub enum BmpMessagePeerDownReason { 30 | AdministrativelyClosed(BgpNotificationMessage), // 1 31 | LocalSystemState(u16), // 2 32 | RemoteNotification(BgpNotificationMessage), // 3 33 | Remote, // 4 34 | BmpDisabled, // 5 35 | } 36 | 37 | #[derive(Debug)] 38 | pub struct BmpMessagePeerDown { 39 | pub peer: BmpMessagePeerHeader, 40 | pub reason: BmpMessagePeerDownReason, 41 | } 42 | 43 | impl BmpMessagePeerUp { 44 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessagePeerUp, usize), BgpError> { 45 | if buf.len() < 62 { 46 | return Err(BgpError::InsufficientBufferSize); 47 | } 48 | let pm = BmpMessagePeerHeader::decode_from(buf)?; 49 | let mut ret = BmpMessagePeerUp { 50 | peer: pm.0, 51 | localaddress: decode_bmp_addr_from(&buf[pm.1..])?, 52 | localport: getn_u16(&buf[pm.1 + 16..]), 53 | remoteport: getn_u16(&buf[pm.1 + 18..]), 54 | msg1: BgpOpenMessage::new(), 55 | msg2: BgpOpenMessage::new(), 56 | }; 57 | let sesspars = BgpSessionParams::from(&ret.peer); 58 | let mut pos: usize = pm.1 + 20; 59 | let msgt = sesspars.decode_message_head(&buf[pos..])?; 60 | pos += 19; 61 | if msgt.0 != BgpMessageType::Open { 62 | return Err(BgpError::static_str("Invalid BGP message type #1")); 63 | } 64 | ret.msg1.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; 65 | pos += msgt.1; 66 | let msgt = sesspars.decode_message_head(&buf[pos..])?; 67 | pos += 19; 68 | if msgt.0 != BgpMessageType::Open { 69 | return Err(BgpError::static_str("Invalid BGP message type #2")); 70 | } 71 | ret.msg2.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; 72 | pos += msgt.1; 73 | Ok((ret, pos)) 74 | } 75 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 76 | if buf.len() < 62 { 77 | return Err(BgpError::InsufficientBufferSize); 78 | } 79 | let mut curpos: usize = 0; 80 | curpos += self.peer.encode_to(buf)?; 81 | 82 | encode_bmp_addr_to(&self.localaddress, &mut buf[curpos..])?; 83 | curpos += 16; 84 | setn_u16(self.localport, &mut buf[curpos..]); 85 | curpos += 2; 86 | setn_u16(self.remoteport, &mut buf[curpos..]); 87 | curpos += 2; 88 | 89 | let sesspars: &BgpSessionParams = &(&self.peer).into(); 90 | 91 | let messagelen = self.msg1.encode_to(sesspars, &mut buf[curpos + 19..])?; 92 | let blen = 93 | sesspars.prepare_message_buf(&mut buf[curpos..], BgpMessageType::Open, messagelen)?; 94 | curpos += blen; 95 | 96 | let messagelen = self.msg2.encode_to(sesspars, &mut buf[curpos + 19..])?; 97 | let blen = 98 | sesspars.prepare_message_buf(&mut buf[curpos..], BgpMessageType::Open, messagelen)?; 99 | curpos += blen; 100 | 101 | Ok(curpos) 102 | } 103 | } 104 | 105 | impl BmpMessagePeerDown { 106 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessagePeerDown, usize), BgpError> { 107 | if buf.len() < 43 { 108 | return Err(BgpError::InsufficientBufferSize); 109 | } 110 | let pm = BmpMessagePeerHeader::decode_from(buf)?; 111 | let mut pos = pm.1; 112 | let reason_code = buf[pos]; 113 | pos += 1; 114 | let reason = match reason_code { 115 | 1 => { 116 | let sesspars = BgpSessionParams::from(&pm.0); 117 | let msgt = sesspars.decode_message_head(&buf[pos..])?; 118 | pos += 19; 119 | if msgt.0 != BgpMessageType::Notification { 120 | return Err(BgpError::static_str("Invalid BGP message type")); 121 | } 122 | let mut msg = BgpNotificationMessage::new(); 123 | msg.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; 124 | pos += msgt.1; 125 | BmpMessagePeerDownReason::AdministrativelyClosed(msg) 126 | } 127 | 2 => { 128 | if buf.len() - pos < 2 { 129 | return Err(BgpError::InsufficientBufferSize); 130 | } 131 | let state = u16::from_be_bytes((&buf[pos..pos + 2]).try_into().unwrap()); 132 | pos += 2; 133 | BmpMessagePeerDownReason::LocalSystemState(state) 134 | } 135 | 3 => { 136 | let sesspars = BgpSessionParams::from(&pm.0); 137 | let msgt = sesspars.decode_message_head(&buf[pos..])?; 138 | pos += 19; 139 | if msgt.0 != BgpMessageType::Notification { 140 | return Err(BgpError::static_str("Invalid BGP message type")); 141 | } 142 | let mut msg = BgpNotificationMessage::new(); 143 | msg.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; 144 | pos += msgt.1; 145 | BmpMessagePeerDownReason::RemoteNotification(msg) 146 | } 147 | 4 => BmpMessagePeerDownReason::Remote, 148 | 5 => BmpMessagePeerDownReason::BmpDisabled, 149 | _ => return Err(BgpError::static_str("Unknown BMP Peer Down Reason Type")), 150 | }; 151 | Ok((BmpMessagePeerDown { peer: pm.0, reason }, pos)) 152 | } 153 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 154 | if buf.len() < 43 { 155 | return Err(BgpError::InsufficientBufferSize); 156 | } 157 | let mut curpos: usize = 0; 158 | curpos += self.peer.encode_to(buf)?; 159 | 160 | match &self.reason { 161 | BmpMessagePeerDownReason::AdministrativelyClosed(msg) => { 162 | buf[curpos] = 1; 163 | curpos += 1; 164 | 165 | if buf.len() - curpos < 19 { 166 | return Err(BgpError::InsufficientBufferSize); 167 | } 168 | 169 | let sesspars: &BgpSessionParams = &(&self.peer).into(); 170 | let messagelen = msg.encode_to(sesspars, &mut buf[curpos + 19..])?; 171 | let blen = sesspars.prepare_message_buf( 172 | &mut buf[curpos..], 173 | BgpMessageType::Notification, 174 | messagelen, 175 | )?; 176 | curpos += blen; 177 | } 178 | BmpMessagePeerDownReason::LocalSystemState(state) => { 179 | buf[curpos] = 2; 180 | curpos += 1; 181 | 182 | if buf.len() - curpos < 2 { 183 | return Err(BgpError::InsufficientBufferSize); 184 | } 185 | setn_u16(*state, &mut buf[curpos..]); 186 | curpos += 2; 187 | } 188 | BmpMessagePeerDownReason::RemoteNotification(msg) => { 189 | buf[curpos] = 3; 190 | curpos += 1; 191 | 192 | if buf.len() - curpos < 19 { 193 | return Err(BgpError::InsufficientBufferSize); 194 | } 195 | 196 | let sesspars: &BgpSessionParams = &(&self.peer).into(); 197 | let messagelen = msg.encode_to(sesspars, &mut buf[curpos + 19..])?; 198 | let blen = sesspars.prepare_message_buf( 199 | &mut buf[curpos..], 200 | BgpMessageType::Notification, 201 | messagelen, 202 | )?; 203 | curpos += blen; 204 | } 205 | BmpMessagePeerDownReason::Remote => { 206 | buf[curpos] = 4; 207 | curpos += 1; 208 | } 209 | BmpMessagePeerDownReason::BmpDisabled => { 210 | buf[curpos] = 5; 211 | curpos += 1; 212 | } 213 | } 214 | 215 | Ok(curpos) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/bmp/msgrmon.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BMP route monitoring message 10 | 11 | use crate::bmp::bmputl::*; 12 | use crate::message::update::BgpUpdateMessage; 13 | use crate::message::*; 14 | use crate::{BgpError, BgpMessage, BgpSessionParams}; 15 | 16 | /// BMP route monitoring message 17 | #[derive(Debug)] 18 | pub struct BmpMessageRouteMonitoring { 19 | /// peer header 20 | pub peer: BmpMessagePeerHeader, 21 | /// incapsulated BGP update message 22 | pub update: BgpUpdateMessage, 23 | } 24 | 25 | impl BmpMessageRouteMonitoring { 26 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageRouteMonitoring, usize), BgpError> { 27 | if buf.len() < 62 { 28 | return Err(BgpError::InsufficientBufferSize); 29 | } 30 | let pm = BmpMessagePeerHeader::decode_from(buf)?; 31 | let mut pos = pm.1; 32 | let sesspars: &BgpSessionParams = &(&pm.0).into(); 33 | let msgt = sesspars.decode_message_head(&buf[pos..])?; 34 | pos += 19; 35 | if msgt.0 != BgpMessageType::Update { 36 | return Err(BgpError::static_str( 37 | "Invalid BGP message type for BmpMessageRouteMonitoring", 38 | )); 39 | } 40 | let mut upd = BgpUpdateMessage::new(); 41 | upd.decode_from(sesspars, &buf[pos..pos + msgt.1])?; 42 | pos += msgt.1; 43 | Ok(( 44 | BmpMessageRouteMonitoring { 45 | peer: pm.0, 46 | update: upd, 47 | }, 48 | pos, 49 | )) 50 | } 51 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 52 | let mut curpos: usize = 0; 53 | if buf.len() < 62 { 54 | return Err(BgpError::InsufficientBufferSize); 55 | } 56 | curpos += self.peer.encode_to(buf)?; 57 | let sesspars: &BgpSessionParams = &(&self.peer).into(); 58 | 59 | let messagelen = self.update.encode_to(sesspars, &mut buf[curpos + 19..])?; 60 | let blen = 61 | sesspars.prepare_message_buf(&mut buf[curpos..], BgpMessageType::Update, messagelen)?; 62 | curpos += blen; 63 | 64 | Ok(curpos) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/bmp/msgterm.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BMP termination message 10 | 11 | use crate::*; 12 | 13 | /// BMP termination message 14 | #[derive(Debug, Clone, PartialEq, Eq)] 15 | pub struct BmpMessageTermination { 16 | /// reason string 17 | pub str0: Option, 18 | /// reason code 19 | pub reason: Option, 20 | } 21 | 22 | impl BmpMessageTermination { 23 | pub fn new() -> BmpMessageTermination { 24 | BmpMessageTermination { 25 | str0: None, 26 | reason: None, 27 | } 28 | } 29 | pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageTermination, usize), BgpError> { 30 | let mut pos: usize = 0; 31 | let mut ret: BmpMessageTermination = BmpMessageTermination::new(); 32 | while buf.len() - pos >= 4 { 33 | let infotype = getn_u16(&buf[pos..]); 34 | let infolen = getn_u16(&buf[pos + 2..]) as usize; 35 | pos += 4; 36 | if buf.len() - pos < infolen { 37 | return Err(BgpError::InsufficientBufferSize); 38 | } 39 | match infotype { 40 | 0 => ret.str0 = Some(core::str::from_utf8(&buf[pos..pos + infolen])?.to_string()), 41 | 1 => ret.reason = Some(getn_u16(&buf[pos..])), 42 | _ => {} 43 | } 44 | pos += infolen; 45 | } 46 | Ok((ret, pos)) 47 | } 48 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 49 | let mut curpos: usize = 0; 50 | if let Some(str0) = &self.str0 { 51 | let str0 = str0.as_bytes(); 52 | if buf.len() - curpos < 4 + str0.len() { 53 | return Err(BgpError::InsufficientBufferSize); 54 | } 55 | setn_u16(0, &mut buf[curpos..]); 56 | curpos += 2; 57 | setn_u16(str0.len() as u16, &mut buf[curpos..]); 58 | curpos += 2; 59 | buf[curpos..curpos + str0.len()].copy_from_slice(str0); 60 | curpos += str0.len(); 61 | } 62 | if let Some(reason) = self.reason { 63 | if buf.len() - curpos < 6 { 64 | return Err(BgpError::InsufficientBufferSize); 65 | } 66 | setn_u16(1, &mut buf[curpos..]); 67 | curpos += 2; 68 | setn_u16(2, &mut buf[curpos..]); 69 | curpos += 2; 70 | setn_u16(reason, &mut buf[curpos..]); 71 | curpos += 2; 72 | } 73 | Ok(curpos) 74 | } 75 | } 76 | impl Default for BmpMessageTermination { 77 | fn default() -> Self { 78 | Self::new() 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/bmp/prelude.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Convenience re-export of common members 10 | //! 11 | //! Like the standard library's prelude, this module simplifies importing of 12 | //! common items. Unlike the standard prelude, the contents of this module must 13 | //! be imported manually: 14 | //! 15 | //! ``` 16 | //! use zettabgp::bmp::prelude::*; 17 | //! ``` 18 | 19 | pub use crate::bmp::bmputl::*; 20 | pub use crate::bmp::msginit::*; 21 | pub use crate::bmp::msgpeer::*; 22 | pub use crate::bmp::msgrmon::*; 23 | pub use crate::bmp::msgterm::*; 24 | pub use crate::bmp::*; 25 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module contains error struct 10 | 11 | /// This is represents standard library error. 12 | /// 13 | /// # Generic usage 14 | /// 15 | /// All library methods that can cause errors returns Result<...,BgpError>. 16 | /// 17 | #[derive(Debug)] 18 | pub enum BgpError { 19 | Static(&'static str), 20 | InsufficientBufferSize, 21 | ProtocolError, 22 | TooManyData, 23 | DynStr(std::string::String), 24 | Other(Box), 25 | } 26 | 27 | impl BgpError { 28 | /// Wraps static string error message. 29 | #[inline] 30 | pub fn static_str(ms: &'static str) -> BgpError { 31 | BgpError::Static(ms) 32 | } 33 | /// Wraps std String error message. 34 | #[inline] 35 | pub fn from_string(s: std::string::String) -> BgpError { 36 | BgpError::DynStr(s) 37 | } 38 | /// Wraps any error implements std::error::Error. In Box. 39 | #[inline] 40 | pub fn from_error(e: Box) -> BgpError { 41 | BgpError::Other(e) 42 | } 43 | /// Just says that buffer size is too small. 44 | #[inline] 45 | pub fn insufficient_buffer_size() -> BgpError { 46 | BgpError::InsufficientBufferSize 47 | } 48 | /// Just says that we have common protocol error. 49 | #[inline] 50 | pub fn protocol_error() -> BgpError { 51 | BgpError::ProtocolError 52 | } 53 | /// Just says that data size is too big to be encoded. 54 | #[inline] 55 | pub fn too_many_data() -> BgpError { 56 | BgpError::TooManyData 57 | } 58 | } 59 | impl std::fmt::Display for BgpError { 60 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 61 | match self { 62 | BgpError::InsufficientBufferSize => write!(f, "BgpError InsufficientBufferSize"), 63 | BgpError::ProtocolError => write!(f, "BgpError ProtocolError"), 64 | BgpError::TooManyData => write!(f, "BgpError TooManyData"), 65 | BgpError::Static(s) => write!(f, "BgpError {}", s), 66 | BgpError::DynStr(s) => write!(f, "BgpError {}", s), 67 | BgpError::Other(e) => write!(f, "BgpError {}", e), 68 | } 69 | } 70 | } 71 | impl std::error::Error for BgpError {} 72 | 73 | impl From for BgpError { 74 | #[inline] 75 | fn from(error: std::io::Error) -> Self { 76 | BgpError::Other(Box::new(error)) 77 | } 78 | } 79 | 80 | impl From for BgpError { 81 | #[inline] 82 | fn from(error: std::net::AddrParseError) -> Self { 83 | BgpError::Other(Box::new(error)) 84 | } 85 | } 86 | 87 | impl From for BgpError { 88 | #[inline] 89 | fn from(error: std::str::Utf8Error) -> Self { 90 | BgpError::Other(Box::new(error)) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/message/attributes/aggregatoras.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "Aggregator AS" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP "Aggregator AS" path attribute struct 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub struct BgpAggregatorAS { 20 | /// Autonomous system number 21 | pub asn: u32, 22 | /// Aggregation router ID 23 | pub addr: std::net::Ipv4Addr, 24 | } 25 | impl BgpAggregatorAS { 26 | pub fn decode_from(_peer: &BgpSessionParams, buf: &[u8]) -> Result { 27 | if buf.len() == 8 { 28 | Ok(BgpAggregatorAS { 29 | asn: getn_u32(buf), 30 | addr: decode_addrv4_from(&buf[4..8])?, 31 | }) 32 | } else if buf.len() == 6 { 33 | Ok(BgpAggregatorAS { 34 | asn: getn_u16(buf) as u32, 35 | addr: decode_addrv4_from(&buf[2..6])?, 36 | }) 37 | } else { 38 | Err(BgpError::static_str("Invalid AggregatorAS length")) 39 | } 40 | } 41 | } 42 | impl std::fmt::Debug for BgpAggregatorAS { 43 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 44 | f.debug_struct("BgpAggregatorAS") 45 | .field("asn", &self.asn) 46 | .field("addr", &self.addr) 47 | .finish() 48 | } 49 | } 50 | impl std::fmt::Display for BgpAggregatorAS { 51 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 52 | write!(f, "BgpAggregatorAS {:?} {:?}", self.asn, self.addr) 53 | } 54 | } 55 | impl BgpAttr for BgpAggregatorAS { 56 | fn attr(&self) -> BgpAttrParams { 57 | BgpAttrParams { 58 | typecode: 7, 59 | flags: 64, 60 | } 61 | } 62 | fn encode_to(&self, peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { 63 | Ok(if peer.has_as32bit { 4 } else { 2 }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/message/attributes/aspath.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "ASpath" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::cmp::Ordering; 15 | use std::hash::{Hash, Hasher}; 16 | 17 | /// BGP AS - element of aspath 18 | #[derive(Clone, Copy, Debug)] 19 | #[cfg(feature = "serialization")] 20 | #[derive(Serialize, Deserialize)] 21 | #[serde(transparent)] 22 | pub struct BgpAS { 23 | pub value: u32, 24 | } 25 | /// BGP as-path path attribute 26 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 27 | #[cfg(feature = "serialization")] 28 | #[derive(Serialize, Deserialize)] 29 | #[serde(transparent)] 30 | pub struct BgpASpath { 31 | pub value: Vec, 32 | } 33 | 34 | impl BgpAS { 35 | pub fn new(v: u32) -> BgpAS { 36 | BgpAS { value: v } 37 | } 38 | pub fn tonumb(&self) -> u32 { 39 | if (self.value & 0xffff) == 0 { 40 | self.value >> 16 41 | } else { 42 | self.value 43 | } 44 | } 45 | } 46 | impl From for BgpAS { 47 | fn from(v: u32) -> Self { 48 | BgpAS { value: v } 49 | } 50 | } 51 | impl PartialEq for BgpAS { 52 | fn eq(&self, other: &Self) -> bool { 53 | self.tonumb() == other.tonumb() 54 | } 55 | } 56 | impl Eq for BgpAS {} 57 | impl PartialOrd for BgpAS { 58 | fn partial_cmp(&self, other: &Self) -> Option { 59 | self.value.partial_cmp(&other.value) 60 | } 61 | } 62 | impl Ord for BgpAS { 63 | fn cmp(&self, other: &Self) -> Ordering { 64 | self.value.cmp(&other.value) 65 | } 66 | } 67 | impl Hash for BgpAS { 68 | fn hash(&self, state: &mut H) { 69 | self.value.hash(state) 70 | } 71 | } 72 | impl std::fmt::Display for BgpAS { 73 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 74 | if (self.value & 0xffff) == 0 { 75 | write!(f, "{}", self.value >> 16) 76 | } else { 77 | write!(f, "{}", self.value) 78 | } 79 | } 80 | } 81 | impl BgpASpath { 82 | pub fn new() -> BgpASpath { 83 | BgpASpath { value: Vec::new() } 84 | } 85 | pub fn from, I: IntoIterator>(sv: I) -> BgpASpath { 86 | BgpASpath { 87 | value: sv.into_iter().map(|q| q.into()).collect(), 88 | } 89 | } 90 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 91 | if buf.len() < 2 { 92 | return Ok(BgpASpath { value: Vec::new() }); 93 | } 94 | let mut pos: usize; 95 | if peer.has_as32bit { 96 | pos = buf.len() % 4; 97 | } else { 98 | pos = buf.len() % 2; 99 | } 100 | let mut v: Vec = Vec::new(); 101 | while pos < buf.len() { 102 | if peer.has_as32bit { 103 | v.push(getn_u32(&buf[pos..(pos + 4)]).into()); 104 | pos += 4; 105 | } else { 106 | v.push((getn_u16(&buf[pos..(pos + 2)]) as u32).into()); 107 | pos += 2; 108 | } 109 | } 110 | Ok(BgpASpath { value: v }) 111 | } 112 | } 113 | impl Default for BgpASpath { 114 | fn default() -> Self { 115 | Self::new() 116 | } 117 | } 118 | impl std::fmt::Debug for BgpASpath { 119 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 120 | f.debug_struct("BgpASpath") 121 | .field("value", &self.value) 122 | .finish() 123 | } 124 | } 125 | impl std::fmt::Display for BgpASpath { 126 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 127 | write!(f, "ASPath {:?}", self.value) 128 | } 129 | } 130 | impl BgpAttr for BgpASpath { 131 | fn attr(&self) -> BgpAttrParams { 132 | BgpAttrParams { 133 | typecode: 2, 134 | flags: 0x50, 135 | } 136 | } 137 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 138 | let mut pos: usize; 139 | if self.value.is_empty() { 140 | return Ok(0); 141 | } 142 | if peer.has_as32bit { 143 | if buf.len() < (2 + self.value.len() * 4) { 144 | return Err(BgpError::insufficient_buffer_size()); 145 | } 146 | buf[0] = 2; //as-sequence 147 | buf[1] = self.value.len() as u8; 148 | pos = 2; 149 | } else { 150 | if buf.len() < (2 + self.value.len() * 2) { 151 | return Err(BgpError::insufficient_buffer_size()); 152 | } 153 | buf[0] = 2; //as-sequence 154 | buf[1] = self.value.len() as u8; 155 | pos = 2; 156 | } 157 | for i in &self.value { 158 | if peer.has_as32bit { 159 | setn_u32(i.value, &mut buf[pos..(pos + 4)]); 160 | pos += 4; 161 | } else { 162 | setn_u16(i.value as u16, &mut buf[pos..(pos + 2)]); 163 | pos += 2; 164 | } 165 | } 166 | Ok(pos) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/message/attributes/atomicaggregate.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "Atomic aggregate" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP Atmic aggregate path attribute 16 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | #[serde(transparent)] 20 | pub struct BgpAtomicAggregate { 21 | pub value: std::net::IpAddr, 22 | } 23 | impl BgpAtomicAggregate { 24 | pub fn decode_from( 25 | _peer: &BgpSessionParams, 26 | buf: &[u8], 27 | ) -> Result { 28 | Ok(BgpAtomicAggregate { 29 | value: if buf.is_empty() { 30 | std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)) 31 | } else { 32 | decode_addr_from(buf)? 33 | }, 34 | }) 35 | } 36 | } 37 | impl std::fmt::Debug for BgpAtomicAggregate { 38 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 39 | f.debug_struct("BgpAtomicAggregate") 40 | .field("value", &self.value) 41 | .finish() 42 | } 43 | } 44 | impl std::fmt::Display for BgpAtomicAggregate { 45 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 46 | self.value.fmt(f) 47 | } 48 | } 49 | impl BgpAttr for BgpAtomicAggregate { 50 | fn attr(&self) -> BgpAttrParams { 51 | BgpAttrParams { 52 | typecode: 6, 53 | flags: 64, 54 | } 55 | } 56 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 57 | encode_addr_to(&self.value, buf) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/message/attributes/attrset.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP attribute set path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP attribute set path attribute struct 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub struct BgpAttrSet { 20 | /// Originating autonomous system number 21 | pub asn: u32, 22 | /// Carried path attributes 23 | pub attrs: Vec, 24 | } 25 | impl BgpAttrSet { 26 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 27 | if !peer.has_as32bit { 28 | return Err(BgpError::static_str( 29 | "Invalid BgpAttrSet without 32-bit AS support", 30 | )); 31 | } 32 | if buf.len() < 4 { 33 | return Err(BgpError::static_str("Invalid BgpAttrSet buffer length")); 34 | } 35 | let mut attrs = Vec::::new(); 36 | let mut curpos = 4; 37 | while curpos < buf.len() { 38 | let flags = buf[curpos]; 39 | let tc = buf[curpos + 1]; 40 | let attrlen = if (flags & 16) > 0 { 41 | curpos += 4; 42 | getn_u16(&buf[(curpos - 2)..curpos]) as usize 43 | } else { 44 | curpos += 3; 45 | buf[curpos - 1] as usize 46 | }; 47 | if (curpos + attrlen) > buf.len() { 48 | return Err(BgpError::static_str("Protocol error")); 49 | }; 50 | attrs.push(BgpAttrItem::decode_from( 51 | peer, 52 | tc, 53 | flags, 54 | attrlen, 55 | &buf[curpos..(curpos + attrlen)], 56 | )?); 57 | curpos += attrlen; 58 | } 59 | Ok(BgpAttrSet { 60 | asn: getn_u32(buf), 61 | attrs, 62 | }) 63 | } 64 | } 65 | impl std::fmt::Debug for BgpAttrSet { 66 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 67 | f.debug_struct("BgpAttrSet") 68 | .field("asn", &self.asn) 69 | .field("attrs", &self.attrs) 70 | .finish() 71 | } 72 | } 73 | impl std::fmt::Display for BgpAttrSet { 74 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 75 | write!(f, "BgpAttrSet AS{} {:?}", self.asn, self.attrs) 76 | } 77 | } 78 | impl BgpAttr for BgpAttrSet { 79 | fn attr(&self) -> BgpAttrParams { 80 | BgpAttrParams { 81 | typecode: 128, 82 | flags: 224, 83 | } 84 | } 85 | fn encode_to(&self, _peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { 86 | unimplemented!() 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/message/attributes/clusterlist.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "cluster list" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP clustr list path attribute struct 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | #[serde(transparent)] 20 | pub struct BgpClusterList { 21 | pub value: Vec, 22 | } 23 | impl BgpClusterList { 24 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 25 | let mut pos: usize = 0; 26 | let mut v = Vec::new(); 27 | let itemsize = match peer.peer_mode { 28 | BgpTransportMode::IPv4 => 4, 29 | BgpTransportMode::IPv6 => 16, 30 | }; 31 | while (pos + itemsize) <= buf.len() { 32 | v.push(decode_addr_from(&buf[pos..(pos + itemsize)])?); 33 | pos += itemsize; 34 | } 35 | Ok(BgpClusterList { value: v }) 36 | } 37 | } 38 | impl std::fmt::Debug for BgpClusterList { 39 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 40 | f.debug_struct("BgpClusterList") 41 | .field("value", &self.value) 42 | .finish() 43 | } 44 | } 45 | impl std::fmt::Display for BgpClusterList { 46 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 47 | write!(f, "BgpClusterList {:?}", self.value) 48 | } 49 | } 50 | impl BgpAttr for BgpClusterList { 51 | fn attr(&self) -> BgpAttrParams { 52 | BgpAttrParams { 53 | typecode: 10, 54 | flags: 0x80, 55 | } 56 | } 57 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 58 | let mut pos: usize = 0; 59 | for i in &self.value { 60 | pos += encode_addr_to(i, &mut buf[pos..])?; 61 | } 62 | Ok(pos) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/message/attributes/community.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "community list" path attributes 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::str::FromStr; 15 | 16 | /// no-export well-known community 17 | pub const NO_EXPORT: BgpCommunity = BgpCommunity{ value:0xffffff01 }; 18 | /// no-advertise well-known community 19 | pub const NO_ADVERTISE: BgpCommunity = BgpCommunity{ value:0xffffff02 }; 20 | /// no-export-subconfed well-known community 21 | pub const NO_EXPORT_SUBCONFED: BgpCommunity = BgpCommunity{ value:0xffffff03 }; 22 | /// no-peer well-known community 23 | pub const NOPEER: BgpCommunity = BgpCommunity{ value:0xffffff04 }; 24 | 25 | /// BGP community - element for BgpCommunityList path attribute 26 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 27 | #[cfg(feature = "serialization")] 28 | #[derive(Serialize, Deserialize)] 29 | #[serde(transparent)] 30 | pub struct BgpCommunity { 31 | pub value: u32, 32 | } 33 | /// BGP community list path attribute 34 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 35 | #[cfg(feature = "serialization")] 36 | #[derive(Serialize, Deserialize)] 37 | #[serde(transparent)] 38 | pub struct BgpCommunityList { 39 | pub value: std::collections::BTreeSet, 40 | } 41 | 42 | /// BGP large community - element for BgpLargeCommunityList path attribute 43 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 44 | #[cfg(feature = "serialization")] 45 | #[derive(Serialize, Deserialize)] 46 | pub struct BgpLargeCommunity { 47 | pub ga: u32, 48 | pub ldp1: u32, 49 | pub ldp2: u32, 50 | } 51 | /// BGP community list path attribute 52 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 53 | #[cfg(feature = "serialization")] 54 | #[derive(Serialize, Deserialize)] 55 | #[serde(transparent)] 56 | pub struct BgpLargeCommunityList { 57 | pub value: std::collections::BTreeSet, 58 | } 59 | impl BgpLargeCommunity { 60 | pub fn decode_from(buf: &[u8]) -> Result { 61 | match buf.len() { 62 | 12 => Ok(BgpLargeCommunity { 63 | ga: getn_u32(&buf[0..4]), 64 | ldp1: getn_u32(&buf[4..8]), 65 | ldp2: getn_u32(&buf[8..12]), 66 | }), 67 | _ => Err(BgpError::static_str( 68 | "Invalid BgpLargeCommunity item length", 69 | )), 70 | } 71 | } 72 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 73 | if buf.len() < 12 { 74 | return Err(BgpError::insufficient_buffer_size()); 75 | } 76 | setn_u32(self.ga, buf); 77 | setn_u32(self.ldp1, &mut buf[4..8]); 78 | setn_u32(self.ldp2, &mut buf[8..12]); 79 | Ok(12) 80 | } 81 | } 82 | impl std::fmt::Debug for BgpLargeCommunity { 83 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 84 | f.debug_struct("Community") 85 | .field("ga", &self.ga) 86 | .field("ldp1", &self.ldp1) 87 | .field("ldp2", &self.ldp2) 88 | .finish() 89 | } 90 | } 91 | impl std::fmt::Display for BgpLargeCommunity { 92 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 93 | write!(f, "{}:{}:{}", self.ga, self.ldp1, self.ldp2) 94 | } 95 | } 96 | impl BgpLargeCommunityList { 97 | pub fn new() -> BgpLargeCommunityList { 98 | BgpLargeCommunityList { 99 | value: std::collections::BTreeSet::new(), 100 | } 101 | } 102 | pub fn decode_from(buf: &[u8]) -> Result { 103 | let mut pos: usize = 0; 104 | let mut v = std::collections::BTreeSet::new(); 105 | while pos < buf.len() { 106 | v.insert(BgpLargeCommunity::decode_from(&buf[pos..(pos + 12)])?); 107 | pos += 12; 108 | } 109 | Ok(BgpLargeCommunityList { value: v }) 110 | } 111 | } 112 | impl std::fmt::Debug for BgpLargeCommunityList { 113 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 114 | f.debug_struct("BgpLargeCommunityList") 115 | .field("value", &self.value) 116 | .finish() 117 | } 118 | } 119 | impl std::fmt::Display for BgpLargeCommunityList { 120 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 121 | write!(f, "BgpLargeCommunityList {:?}", self.value) 122 | } 123 | } 124 | impl BgpAttr for BgpLargeCommunityList { 125 | fn attr(&self) -> BgpAttrParams { 126 | BgpAttrParams { 127 | typecode: 32, 128 | flags: 128 | 64 | 32 | 16, 129 | } 130 | } 131 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 132 | let mut pos: usize = 0; 133 | for i in &self.value { 134 | pos += i.encode_to(&mut buf[pos..])?; 135 | } 136 | Ok(pos) 137 | } 138 | } 139 | impl Default for BgpLargeCommunityList { 140 | fn default() -> Self { 141 | Self::new() 142 | } 143 | } 144 | impl BgpCommunity { 145 | const NO_EXPORT_STR0:&str="no_export"; 146 | const NO_EXPORT_STR1:&str="noexport"; 147 | const NO_EXPORT_STR2:&str="no-export"; 148 | const NO_ADVERTISE_STR0:&str="no_advertise"; 149 | const NO_ADVERTISE_STR1:&str="no-advertise"; 150 | const NO_EXPORT_SUBCONFED_STR:&str="no_export_subconfed"; 151 | const NOPEER_STR0:&str="nopeer"; 152 | const NOPEER_STR1:&str="no-peer"; 153 | pub fn new(v: u32) -> BgpCommunity { 154 | BgpCommunity { value: v } 155 | } 156 | pub fn from(h: u16, l: u16) -> BgpCommunity { 157 | BgpCommunity { 158 | value: ((h as u32) << 16) | (l as u32), 159 | } 160 | } 161 | pub fn decode_from(buf: &[u8]) -> Result { 162 | match buf.len() { 163 | 4 => Ok(BgpCommunity { 164 | value: getn_u32(buf), 165 | }), 166 | _ => Err(BgpError::static_str("Invalid BgpCommunity item length")), 167 | } 168 | } 169 | fn encode_to(&self, buf: &mut [u8]) -> Result { 170 | if buf.len() < 4 { 171 | return Err(BgpError::insufficient_buffer_size()); 172 | }; 173 | setn_u32(self.value, buf); 174 | Ok(4) 175 | } 176 | } 177 | impl std::fmt::Debug for BgpCommunity { 178 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 179 | f.debug_struct("Community") 180 | .field("value", &self.value) 181 | .finish() 182 | } 183 | } 184 | impl std::fmt::Display for BgpCommunity { 185 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 186 | match self { 187 | &NO_EXPORT => f.write_str(Self::NO_EXPORT_STR0), 188 | &NO_ADVERTISE => f.write_str(Self::NO_ADVERTISE_STR0), 189 | &NO_EXPORT_SUBCONFED => f.write_str(Self::NO_EXPORT_SUBCONFED_STR), 190 | &NOPEER => f.write_str(Self::NOPEER_STR0), 191 | _ => write!( 192 | f, 193 | "{}:{}", 194 | (self.value >> 16) as u16, 195 | (self.value & 0xffff) as u16 196 | ) 197 | } 198 | } 199 | } 200 | impl FromStr for BgpCommunity { 201 | type Err = std::num::ParseIntError; 202 | 203 | fn from_str(s: &str) -> Result { 204 | match s { 205 | Self::NO_EXPORT_STR0 | Self::NO_EXPORT_STR1 | Self::NO_EXPORT_STR2 => return Ok(NO_EXPORT.clone()), 206 | Self::NO_ADVERTISE_STR0 | Self::NO_ADVERTISE_STR1 => return Ok(NO_ADVERTISE.clone()), 207 | Self::NO_EXPORT_SUBCONFED_STR => return Ok(NO_EXPORT_SUBCONFED.clone()), 208 | Self::NOPEER_STR0 | Self::NOPEER_STR1 => return Ok(NOPEER.clone()), 209 | _ => {} 210 | }; 211 | let parts: Vec<&str> = s.trim().split(':').collect(); 212 | if parts.len() < 2 { 213 | Ok(BgpCommunity { 214 | value: parts[0].parse()?, 215 | }) 216 | } else if parts.len() < 3 { 217 | Ok(BgpCommunity { 218 | value: (parts[0].parse::()? as u32) << 16 | (parts[1].parse::()? as u32), 219 | }) 220 | } else { 221 | Ok(BgpCommunity { value: s.parse()? }) 222 | } 223 | } 224 | } 225 | 226 | /// BGP community list path attribute 227 | impl BgpCommunityList { 228 | pub fn new() -> BgpCommunityList { 229 | BgpCommunityList { 230 | value: std::collections::BTreeSet::new(), 231 | } 232 | } 233 | pub fn from_vec(v: Vec) -> BgpCommunityList { 234 | BgpCommunityList { 235 | value: v.into_iter().collect(), 236 | } 237 | } 238 | } 239 | impl Default for BgpCommunityList { 240 | fn default() -> Self { 241 | Self::new() 242 | } 243 | } 244 | impl BgpCommunityList { 245 | pub fn decode_from(buf: &[u8]) -> Result { 246 | let mut pos: usize = 0; 247 | let mut v = std::collections::BTreeSet::new(); 248 | while pos < buf.len() { 249 | v.insert(BgpCommunity::decode_from(&buf[pos..(pos + 4)])?); 250 | pos += 4; 251 | } 252 | Ok(BgpCommunityList { value: v }) 253 | } 254 | } 255 | impl std::fmt::Debug for BgpCommunityList { 256 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 257 | f.debug_struct("BgpCommunityList") 258 | .field("value", &self.value) 259 | .finish() 260 | } 261 | } 262 | impl std::fmt::Display for BgpCommunityList { 263 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 264 | write!(f, "BgpCommunityList {:?}", self.value) 265 | } 266 | } 267 | impl FromStr for BgpCommunityList { 268 | type Err = BgpError; 269 | 270 | fn from_str(s: &str) -> Result { 271 | let strs: Vec<&str> = s.split(&[',', ' ', '\t'][..]).collect(); 272 | let mut v = std::collections::BTreeSet::new(); 273 | for s in strs.iter() { 274 | if let Ok(c) = s.parse() { 275 | v.insert(c); 276 | } 277 | } 278 | Ok(BgpCommunityList { value: v }) 279 | } 280 | } 281 | impl BgpAttr for BgpCommunityList { 282 | fn attr(&self) -> BgpAttrParams { 283 | BgpAttrParams { 284 | typecode: 8, 285 | flags: 128 | 64 | 16, 286 | } 287 | } 288 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 289 | if buf.len() < self.value.len() * 4 { 290 | return Err(BgpError::insufficient_buffer_size()); 291 | } 292 | let mut curpos: usize = 0; 293 | for c in &self.value { 294 | let lng = c.encode_to(&mut buf[curpos..])?; 295 | curpos += lng; 296 | } 297 | Ok(curpos) 298 | } 299 | } 300 | #[cfg(test)] 301 | mod tests { 302 | use super::*; 303 | 304 | #[test] 305 | fn test_community_parse() { 306 | assert_eq!( 307 | "no_export".parse::(), 308 | Ok(NO_EXPORT.clone()) 309 | ); 310 | assert_eq!( 311 | "23:45".parse::(), 312 | Ok(BgpCommunity{ value: 0x0017002d }) 313 | ); 314 | } 315 | #[test] 316 | fn test_community_format() { 317 | assert_eq!( 318 | format!("{}",BgpCommunity{ value:0xffffff01 }), 319 | "no_export".to_string() 320 | ); 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/message/attributes/connector.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2022 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "connector" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::net::Ipv4Addr; 15 | 16 | /// BGP local preference path attribute 17 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 18 | #[cfg(feature = "serialization")] 19 | #[derive(Serialize, Deserialize)] 20 | pub struct BgpConnector { 21 | pub asn: u32, 22 | pub addr: Ipv4Addr, 23 | pub orig: Ipv4Addr, 24 | } 25 | impl BgpConnector { 26 | pub fn new(asn: u32, addr: Ipv4Addr, orig: Ipv4Addr) -> BgpConnector { 27 | BgpConnector { asn, addr, orig } 28 | } 29 | pub fn decode_from(buf: &[u8]) -> Result { 30 | if buf.len() >= 14 { 31 | if getn_u16(buf) != 1 { 32 | return Err(BgpError::static_str("Unknown Connector type")); 33 | } 34 | Ok(BgpConnector { 35 | asn: getn_u32(&buf[2..6]), 36 | addr: decode_addrv4_from(&buf[6..10])?, 37 | orig: decode_addrv4_from(&buf[10..14])?, 38 | }) 39 | } else { 40 | Err(BgpError::static_str("Invalid Connector length")) 41 | } 42 | } 43 | } 44 | impl std::fmt::Debug for BgpConnector { 45 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 46 | f.debug_struct("BgpConnector") 47 | .field("asn", &self.asn) 48 | .field("addr", &self.addr) 49 | .field("orig", &self.orig) 50 | .finish() 51 | } 52 | } 53 | impl std::fmt::Display for BgpConnector { 54 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 55 | write!( 56 | f, 57 | "BgpConnector({:?}:{:?} @{:?})", 58 | self.asn, self.addr, self.orig 59 | ) 60 | } 61 | } 62 | impl BgpAttr for BgpConnector { 63 | fn attr(&self) -> BgpAttrParams { 64 | BgpAttrParams { 65 | typecode: 20, 66 | flags: 192, 67 | } 68 | } 69 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 70 | if buf.len() >= 14 { 71 | setn_u16(1, buf); 72 | setn_u32(self.asn, &mut buf[2..6]); 73 | encode_addrv4_to(&self.addr, &mut buf[6..10])?; 74 | encode_addrv4_to(&self.orig, &mut buf[10..14])?; 75 | Ok(14) 76 | } else { 77 | Err(BgpError::static_str("Invalid localpref length")) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/message/attributes/extcommunity.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "extended community list" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP extended community - element for BgpExtCommunityList path attribute 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub struct BgpExtCommunity { 20 | pub ctype: u8, 21 | pub subtype: u8, 22 | pub a: u16, 23 | pub b: u32, 24 | } 25 | impl BgpExtCommunity { 26 | /// creates route-target with AS + number 27 | pub fn rt_asn(asn: u16, val: u32) -> BgpExtCommunity { 28 | BgpExtCommunity { 29 | ctype: 0, 30 | subtype: 2, 31 | a: asn, 32 | b: val, 33 | } 34 | } 35 | /// creates route-target with IP + number 36 | pub fn rt_ipn(ipa: std::net::Ipv4Addr, val: u16) -> BgpExtCommunity { 37 | let octs = ipa.octets(); 38 | BgpExtCommunity { 39 | ctype: 1, 40 | subtype: 2, 41 | a: (octs[0] as u16) << 8 | (octs[1] as u16), 42 | b: (octs[2] as u32) << 24 | (octs[3] as u32) << 16 | (val as u32), 43 | } 44 | } 45 | pub fn decode_from(buf: &[u8]) -> Result { 46 | match buf.len() { 47 | 8 => Ok(BgpExtCommunity { 48 | ctype: buf[0], 49 | subtype: buf[1], 50 | a: getn_u16(&buf[2..4]), 51 | b: getn_u32(&buf[4..8]), 52 | }), 53 | _ => Err(BgpError::static_str("Invalid BgpExtCommunity item length")), 54 | } 55 | } 56 | pub fn encode_to(&self, buf: &mut [u8]) -> Result { 57 | if buf.len() < 8 { 58 | return Err(BgpError::insufficient_buffer_size()); 59 | } 60 | buf[0] = self.ctype; 61 | buf[1] = self.subtype; 62 | setn_u16(self.a, &mut buf[2..4]); 63 | setn_u32(self.b, &mut buf[4..8]); 64 | Ok(8) 65 | } 66 | /// extracts encoded ipv4 67 | pub fn get_ipv4(&self) -> std::net::Ipv4Addr { 68 | std::net::Ipv4Addr::new( 69 | ((self.a >> 8) & 0xff) as u8, 70 | (self.a & 0xff) as u8, 71 | ((self.b >> 24) & 0xff) as u8, 72 | ((self.b >> 16) & 0xff) as u8, 73 | ) 74 | } 75 | /// extracts encoded number 76 | pub fn get_num(&self) -> u16 { 77 | (self.b & 0xffff) as u16 78 | } 79 | } 80 | impl std::fmt::Debug for BgpExtCommunity { 81 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 82 | f.debug_struct("BgpExtCommunity") 83 | .field("ctype", &self.ctype) 84 | .field("subtype", &self.subtype) 85 | .field("a", &self.a) 86 | .field("b", &self.b) 87 | .finish() 88 | } 89 | } 90 | impl std::fmt::Display for BgpExtCommunity { 91 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 92 | if self.subtype == 2 && self.ctype == 0 { 93 | //rt AS-based 94 | write!(f, "ext-target:{}:{}", self.a, self.b) 95 | } else if self.subtype == 2 && self.ctype == 1 { 96 | //rt ip-based 97 | write!(f, "ext-target:{}:{}", self.get_ipv4(), self.get_num()) 98 | } else if self.subtype == 2 && self.ctype == 2 { 99 | //rt ? 100 | write!(f, "ext-target:{}:{}:{}", self.ctype, self.a, self.b) 101 | } else if self.subtype == 3 && self.ctype == 1 { 102 | write!(f, "ext-origin:{}:{}", self.get_ipv4(), self.get_num()) 103 | } else if self.subtype == 3 && self.ctype < 3 { 104 | write!(f, "ext-origin:{}:{}:{}", self.ctype, self.a, self.b) 105 | } else if self.subtype == 9 { 106 | write!(f, "ext-src-as:{}:{}:{}", self.ctype, self.a, self.b) 107 | } else if self.subtype == 11 && self.ctype == 1 { 108 | write!(f, "ext-rt-import:{}:{}", self.get_ipv4(), self.get_num()) 109 | } else if self.subtype == 11 && self.ctype < 3 { 110 | write!(f, "ext-rt-import:{}:{}:{}", self.ctype, self.a, self.b) 111 | } else if self.ctype == 0 || self.ctype == 0x40 { 112 | //as-specific 113 | write!( 114 | f, 115 | "ext-as-specific:0x{:x}:0x{:x}:0x{:x}:0x{:x}", 116 | self.ctype, self.subtype, self.a, self.b 117 | ) 118 | } else if self.subtype == 10 && (self.ctype == 1 || self.ctype == 0x41) { 119 | write!(f, "ext-import-rt:{}:{}", self.get_ipv4(), self.get_num()) 120 | } else if self.ctype == 1 || self.ctype == 0x41 { 121 | //ipv4-specific 122 | write!( 123 | f, 124 | "ext-ipv4a-specific:0x{:x}:0x{:x}:0x{:x}:0x{:x}", 125 | self.ctype, self.subtype, self.a, self.b 126 | ) 127 | } else if self.ctype == 3 && self.subtype == 12 { 128 | write!(f, "encapsulation:0x{:x}", self.b) 129 | } else if self.ctype == 6 && self.subtype == 0x4 { 130 | //evpn-l2-attr 131 | write!(f, "evpn-l2-info:cf={}:mtu={}", self.a, self.b >> 16) 132 | } else if self.ctype == 6 && self.subtype == 1 { 133 | //esi-label 134 | write!( 135 | f, 136 | "esi-label:{}:label={}:{}", 137 | self.a, 138 | self.b >> 8, 139 | self.b & 0xff 140 | ) 141 | } else if self.ctype == 3 || self.ctype == 0x43 { 142 | //opaque 143 | write!( 144 | f, 145 | "ext-opaque:0x{:02x}:0x{:02x}:0x{:x}:0x{:x}", 146 | self.ctype, self.subtype, self.a, self.b 147 | ) 148 | } else { 149 | write!( 150 | f, 151 | "ext-unknown:0x{:02x}:0x{:02x}:0x{:x}:0x{:x}", 152 | self.ctype, self.subtype, self.a, self.b 153 | ) 154 | } 155 | } 156 | } 157 | impl std::convert::From for BgpExtCommunity { 158 | fn from(value: u64) -> Self { 159 | let buf = value.to_be_bytes(); 160 | Self { 161 | ctype: buf[0], 162 | subtype: buf[1], 163 | a: getn_u16(&buf[2..4]), 164 | b: getn_u32(&buf[4..8]), 165 | } 166 | } 167 | } 168 | 169 | /// BGP extended community list path attribute 170 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 171 | #[cfg(feature = "serialization")] 172 | #[derive(Serialize, Deserialize)] 173 | #[serde(transparent)] 174 | pub struct BgpExtCommunityList { 175 | pub value: std::collections::BTreeSet, 176 | } 177 | impl BgpExtCommunityList { 178 | pub fn new() -> BgpExtCommunityList { 179 | BgpExtCommunityList { 180 | value: std::collections::BTreeSet::new(), 181 | } 182 | } 183 | pub fn from_vec(v: Vec) -> BgpExtCommunityList { 184 | let mut vs = std::collections::BTreeSet::new(); 185 | for i in v { 186 | vs.insert(i); 187 | } 188 | BgpExtCommunityList { value: vs } 189 | } 190 | pub fn decode_from(buf: &[u8]) -> Result { 191 | let mut v = std::collections::BTreeSet::new(); 192 | let mut pos: usize = 0; 193 | while (pos + 7) < buf.len() { 194 | v.insert(BgpExtCommunity::decode_from(&buf[pos..(pos + 8)])?); 195 | pos += 8; 196 | } 197 | Ok(BgpExtCommunityList { value: v }) 198 | } 199 | } 200 | impl Default for BgpExtCommunityList { 201 | fn default() -> Self { 202 | Self::new() 203 | } 204 | } 205 | impl std::fmt::Debug for BgpExtCommunityList { 206 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 207 | f.debug_struct("BgpExtCommunityList") 208 | .field("value", &self.value) 209 | .finish() 210 | } 211 | } 212 | impl std::fmt::Display for BgpExtCommunityList { 213 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 214 | write!(f, "BgpExtCommunityList {:?}", self.value) 215 | } 216 | } 217 | impl BgpAttr for BgpExtCommunityList { 218 | fn attr(&self) -> BgpAttrParams { 219 | BgpAttrParams { 220 | typecode: 16, 221 | flags: 192, 222 | } 223 | } 224 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 225 | let mut pos: usize = 0; 226 | for c in &self.value { 227 | let ln = c.encode_to(&mut buf[pos..])?; 228 | pos += ln; 229 | } 230 | Ok(pos) 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/message/attributes/localpref.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "local preference" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP local preference path attribute 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | #[serde(transparent)] 20 | pub struct BgpLocalpref { 21 | pub value: u32, 22 | } 23 | impl BgpLocalpref { 24 | pub fn new(v: u32) -> BgpLocalpref { 25 | BgpLocalpref { value: v } 26 | } 27 | pub fn decode_from(buf: &[u8]) -> Result { 28 | if buf.len() >= 4 { 29 | Ok(BgpLocalpref { 30 | value: getn_u32(buf), 31 | }) 32 | } else { 33 | Err(BgpError::static_str("Invalid localpref length")) 34 | } 35 | } 36 | } 37 | impl std::fmt::Debug for BgpLocalpref { 38 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 39 | f.debug_struct("BgpLocalpref") 40 | .field("value", &self.value) 41 | .finish() 42 | } 43 | } 44 | impl std::fmt::Display for BgpLocalpref { 45 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 46 | write!(f, "BgpLocalpref {:?}", self.value) 47 | } 48 | } 49 | impl BgpAttr for BgpLocalpref { 50 | fn attr(&self) -> BgpAttrParams { 51 | BgpAttrParams { 52 | typecode: 5, 53 | flags: 64, 54 | } 55 | } 56 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 57 | if buf.len() >= 4 { 58 | setn_u32(self.value, buf); 59 | Ok(4) 60 | } else { 61 | Err(BgpError::static_str("Invalid localpref length")) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/message/attributes/med.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP "multi-exit discriminator" path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP MED (multi-exit discriminator) path attribute 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | #[serde(transparent)] 20 | pub struct BgpMED { 21 | pub value: u32, 22 | } 23 | impl BgpMED { 24 | pub fn new(v: u32) -> BgpMED { 25 | BgpMED { value: v } 26 | } 27 | pub fn decode_from(buf: &[u8]) -> Result { 28 | if buf.len() >= 4 { 29 | Ok(BgpMED { 30 | value: getn_u32(buf), 31 | }) 32 | } else { 33 | Err(BgpError::static_str("Invalid MED length")) 34 | } 35 | } 36 | } 37 | impl std::fmt::Debug for BgpMED { 38 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 39 | f.debug_struct("BgpMED") 40 | .field("value", &self.value) 41 | .finish() 42 | } 43 | } 44 | impl std::fmt::Display for BgpMED { 45 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 46 | write!(f, "BgpMED {:?}", self.value) 47 | } 48 | } 49 | impl BgpAttr for BgpMED { 50 | fn attr(&self) -> BgpAttrParams { 51 | BgpAttrParams { 52 | typecode: 4, 53 | flags: 128, 54 | } 55 | } 56 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 57 | if buf.len() >= 4 { 58 | setn_u32(self.value, buf); 59 | Ok(4) 60 | } else { 61 | Err(BgpError::static_str("Invalid MED length")) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/message/attributes/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module contains BGP path attributes 10 | use crate::*; 11 | pub mod aggregatoras; 12 | pub mod aspath; 13 | pub mod atomicaggregate; 14 | pub mod attrset; 15 | pub mod clusterlist; 16 | pub mod community; 17 | pub mod connector; 18 | pub mod extcommunity; 19 | pub mod localpref; 20 | pub mod med; 21 | pub mod multiproto; 22 | pub mod nexthop; 23 | pub mod origin; 24 | pub mod originatorid; 25 | pub mod pmsitunnelattr; 26 | pub mod unknown; 27 | #[cfg(feature = "serialization")] 28 | use serde::{Deserialize, Serialize}; 29 | 30 | use aggregatoras::BgpAggregatorAS; 31 | use aspath::BgpASpath; 32 | use atomicaggregate::BgpAtomicAggregate; 33 | use attrset::BgpAttrSet; 34 | use clusterlist::BgpClusterList; 35 | use community::{BgpCommunityList, BgpLargeCommunityList}; 36 | use connector::BgpConnector; 37 | use extcommunity::BgpExtCommunityList; 38 | use localpref::BgpLocalpref; 39 | use med::BgpMED; 40 | use multiproto::{BgpMPUpdates, BgpMPWithdraws}; 41 | use nexthop::BgpNextHop; 42 | use origin::BgpOrigin; 43 | use originatorid::BgpOriginatorID; 44 | use pmsitunnelattr::BgpPMSITunnel; 45 | use unknown::BgpAttrUnknown; 46 | 47 | /// BGP path attribute mandatory parameters - typecode and flags 48 | #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 49 | #[cfg(feature = "serialization")] 50 | #[derive(Serialize, Deserialize)] 51 | pub struct BgpAttrParams { 52 | pub typecode: u8, 53 | pub flags: u8, 54 | } 55 | 56 | pub trait BgpAttr: std::fmt::Display + std::fmt::Debug { 57 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result; 58 | fn attr(&self) -> BgpAttrParams; 59 | } 60 | 61 | /// BGP path attribute 62 | #[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] 63 | #[cfg(feature = "serialization")] 64 | #[derive(Serialize, Deserialize)] 65 | pub enum BgpAttrItem { 66 | Origin(BgpOrigin), 67 | ASPath(BgpASpath), 68 | NextHop(BgpNextHop), 69 | MED(BgpMED), 70 | LocalPref(BgpLocalpref), 71 | AtomicAggregate(BgpAtomicAggregate), 72 | AggregatorAS(BgpAggregatorAS), 73 | CommunityList(BgpCommunityList), 74 | OriginatorID(BgpOriginatorID), 75 | ClusterList(BgpClusterList), 76 | MPUpdates(BgpMPUpdates), 77 | MPWithdraws(BgpMPWithdraws), 78 | ExtCommunityList(BgpExtCommunityList), 79 | LargeCommunityList(BgpLargeCommunityList), 80 | PMSITunnel(BgpPMSITunnel), 81 | AttrSet(BgpAttrSet), 82 | Connector(BgpConnector), 83 | Unknown(BgpAttrUnknown), 84 | } 85 | 86 | impl BgpAttrItem { 87 | pub fn decode_from( 88 | peer: &BgpSessionParams, 89 | typecode: u8, 90 | flags: u8, 91 | attrlen: usize, 92 | buf: &[u8], 93 | ) -> Result { 94 | match typecode { 95 | 1 => Ok(BgpAttrItem::Origin(BgpOrigin::decode_from(buf)?)), 96 | 2 => Ok(BgpAttrItem::ASPath(BgpASpath::decode_from(peer, buf)?)), 97 | 3 => Ok(BgpAttrItem::NextHop(BgpNextHop::decode_from(peer, buf)?)), 98 | 4 => Ok(BgpAttrItem::MED(BgpMED::decode_from(buf)?)), 99 | 5 => Ok(BgpAttrItem::LocalPref(BgpLocalpref::decode_from(buf)?)), 100 | 6 => Ok(BgpAttrItem::AtomicAggregate( 101 | BgpAtomicAggregate::decode_from(peer, buf)?, 102 | )), 103 | 7 => Ok(BgpAttrItem::AggregatorAS(BgpAggregatorAS::decode_from( 104 | peer, buf, 105 | )?)), 106 | 8 => Ok(BgpAttrItem::CommunityList(BgpCommunityList::decode_from( 107 | buf, 108 | )?)), 109 | 9 => Ok(BgpAttrItem::OriginatorID(BgpOriginatorID::decode_from( 110 | peer, buf, 111 | )?)), 112 | 10 => Ok(BgpAttrItem::ClusterList(BgpClusterList::decode_from( 113 | peer, buf, 114 | )?)), 115 | 14 => Ok(BgpAttrItem::MPUpdates(BgpMPUpdates::decode_from( 116 | peer, buf, 117 | )?)), 118 | 15 => Ok(BgpAttrItem::MPWithdraws(BgpMPWithdraws::decode_from( 119 | peer, buf, 120 | )?)), 121 | 16 => Ok(BgpAttrItem::ExtCommunityList( 122 | BgpExtCommunityList::decode_from(buf)?, 123 | )), 124 | 22 => Ok(BgpAttrItem::PMSITunnel(BgpPMSITunnel::decode_from( 125 | peer, buf, 126 | )?)), 127 | 20 => Ok(BgpAttrItem::Connector(BgpConnector::decode_from(buf)?)), 128 | 32 => Ok(BgpAttrItem::LargeCommunityList( 129 | BgpLargeCommunityList::decode_from(buf)?, 130 | )), 131 | 21 => 132 | //deprecated 133 | { 134 | Ok(BgpAttrItem::Unknown(BgpAttrUnknown::decode_from( 135 | typecode, 136 | flags, 137 | &buf[0..attrlen], 138 | )?)) 139 | } 140 | 128 => Ok(BgpAttrItem::AttrSet(BgpAttrSet::decode_from(peer, buf)?)), 141 | _ => { 142 | log::trace!( 143 | "Unknown PA TC={:?} flags={:?} len={:?}: {:?}", 144 | typecode, 145 | flags, 146 | attrlen, 147 | &buf[0..attrlen] 148 | ); 149 | Ok(BgpAttrItem::Unknown(BgpAttrUnknown::decode_from( 150 | typecode, 151 | flags, 152 | &buf[0..attrlen], 153 | )?)) 154 | } 155 | } 156 | } 157 | fn encode_bgpattr( 158 | attr: &impl BgpAttr, 159 | peer: &BgpSessionParams, 160 | buf: &mut [u8], 161 | ) -> Result { 162 | let attrparams = attr.attr(); 163 | buf[0] = attrparams.flags; 164 | buf[1] = attrparams.typecode; 165 | let mut curpos: usize = 2; 166 | if (attrparams.flags & 16) > 0 { 167 | curpos += 2; 168 | } else { 169 | curpos += 1; 170 | } 171 | let attrlen = attr.encode_to(peer, &mut buf[curpos..])?; 172 | if (attrparams.flags & 16) > 0 { 173 | if attrlen > 65535 { 174 | return Err(BgpError::static_str("Invalid path attribute length")); 175 | } 176 | setn_u16(attrlen as u16, &mut buf[2..4]); 177 | } else { 178 | if attrlen > 255 { 179 | return Err(BgpError::static_str("Invalid path attribute length")); 180 | } 181 | buf[2] = attrlen as u8; 182 | } 183 | Ok(curpos + attrlen) 184 | } 185 | pub fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 186 | match self { 187 | BgpAttrItem::Origin(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 188 | BgpAttrItem::ASPath(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 189 | BgpAttrItem::NextHop(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 190 | BgpAttrItem::MED(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 191 | BgpAttrItem::LocalPref(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 192 | BgpAttrItem::AtomicAggregate(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 193 | BgpAttrItem::AggregatorAS(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 194 | BgpAttrItem::CommunityList(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 195 | BgpAttrItem::OriginatorID(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 196 | BgpAttrItem::ClusterList(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 197 | BgpAttrItem::MPUpdates(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 198 | BgpAttrItem::MPWithdraws(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 199 | BgpAttrItem::ExtCommunityList(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 200 | BgpAttrItem::LargeCommunityList(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 201 | BgpAttrItem::PMSITunnel(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 202 | BgpAttrItem::AttrSet(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 203 | BgpAttrItem::Connector(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 204 | BgpAttrItem::Unknown(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/message/attributes/multiproto.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP multiprotocol update and withdraw path attributes, which carries routing information with mp-bgp 10 | use crate::prelude::*; 11 | #[cfg(feature = "serialization")] 12 | use serde::{Deserialize, Serialize}; 13 | 14 | /// BGP multiprotocol updates 15 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 16 | #[cfg(feature = "serialization")] 17 | #[derive(Serialize, Deserialize)] 18 | pub struct BgpMPUpdates { 19 | /// next hop for this updates 20 | pub nexthop: BgpAddr, 21 | /// NLRI 22 | pub addrs: BgpAddrs, 23 | } 24 | impl BgpMPUpdates { 25 | /// Creates update for VPNv4 unicast 26 | pub fn s4vpnv4u(nhop: BgpIPv4RD, nlri: Vec>>) -> BgpMPUpdates { 27 | BgpMPUpdates { 28 | nexthop: BgpAddr::V4RD(nhop), 29 | addrs: BgpAddrs::VPNV4U(nlri), 30 | } 31 | } 32 | /// Creates update for VPNv4 multicast 33 | pub fn s4vpnv4m(nhop: BgpIPv4RD, nlri: Vec>>) -> BgpMPUpdates { 34 | BgpMPUpdates { 35 | nexthop: BgpAddr::V4RD(nhop), 36 | addrs: BgpAddrs::VPNV4M(nlri), 37 | } 38 | } 39 | /// Creates update for IPv4 labeled unicast 40 | pub fn s4ip4lu(nhop: std::net::Ipv4Addr, nlri: Vec>) -> BgpMPUpdates { 41 | BgpMPUpdates { 42 | nexthop: BgpAddr::V4(nhop), 43 | addrs: BgpAddrs::IPV4LU(nlri), 44 | } 45 | } 46 | /// Creates update for IPv6 labeled unicast 47 | pub fn s4ip6lu(nhop: std::net::Ipv4Addr, nlri: Vec>) -> BgpMPUpdates { 48 | BgpMPUpdates { 49 | nexthop: BgpAddr::V4(nhop), 50 | addrs: BgpAddrs::IPV6LU(nlri), 51 | } 52 | } 53 | /// Creates update for VPNv6 unicast 54 | pub fn s4vpnv6u(nhop: BgpIPv4RD, nlri: Vec>>) -> BgpMPUpdates { 55 | BgpMPUpdates { 56 | nexthop: BgpAddr::V4RD(nhop), 57 | addrs: BgpAddrs::VPNV6U(nlri), 58 | } 59 | } 60 | /// Creates update for VPNv6 multicast 61 | pub fn s4vpnv6m(nhop: BgpIPv4RD, nlri: Vec>>) -> BgpMPUpdates { 62 | BgpMPUpdates { 63 | nexthop: BgpAddr::V4RD(nhop), 64 | addrs: BgpAddrs::VPNV6M(nlri), 65 | } 66 | } 67 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 68 | let afi = getn_u16(buf); 69 | let safi = buf[2]; 70 | let mut curpos: usize = 4; 71 | let nh: BgpAddr; 72 | let nhlen = buf[3] as usize; 73 | match afi { 74 | 1 => { 75 | //ipv4 76 | match safi { 77 | 1 | 2 | 4 | 5 | 66 | 133 => { 78 | //unicast|multicast|labeled unicast|mvpn|mdt|flow 79 | nh = BgpAddr::V4(decode_addrv4_from(&buf[curpos..(curpos + nhlen)])?); 80 | curpos += nhlen; 81 | } 82 | 128 | 129 | 134 => { 83 | //vpnv4u|vpnv4m|flow 84 | let r = BgpIPv4RD::decode_from(peer.peer_mode, &buf[curpos..])?; 85 | nh = BgpAddr::V4RD(r.0); 86 | curpos += r.1; 87 | } 88 | n => { 89 | log::trace!("AFI/SAFI {}/{} {:?}", afi, safi, &buf[curpos..]); 90 | return Err(BgpError::from_string(format!( 91 | "Unknown safi for ipv4 code {:?}", 92 | n 93 | ))); 94 | } 95 | } 96 | } 97 | 2 => { 98 | //ipv6 99 | match safi { 100 | 1 | 2 | 4 | 66 => { 101 | //unicast|multicast|labeled unicast|mdt 102 | nh = BgpAddr::V6(decode_addrv6_from(&buf[curpos..(curpos + nhlen)])?); 103 | curpos += nhlen; 104 | } 105 | 128 | 129 => { 106 | //vpnv6u|vpnv6m 107 | let r = BgpIPv6RD::decode_from(peer.peer_mode, &buf[curpos..])?; 108 | nh = BgpAddr::V6RD(r.0); 109 | curpos += r.1; 110 | } 111 | n => { 112 | return Err(BgpError::from_string(format!( 113 | "Unknown safi for ipv6: {:?}", 114 | n 115 | ))) 116 | } 117 | } 118 | } 119 | 25 => { 120 | //l2 121 | match safi { 122 | 65 | 70 => { 123 | //vpls + evpn 124 | nh = BgpAddr::V4(decode_addrv4_from(&buf[curpos..])?); 125 | curpos += nhlen; 126 | } 127 | n => { 128 | return Err(BgpError::from_string(format!( 129 | "Unknown safi for l2: {:?}", 130 | n 131 | ))) 132 | } 133 | } 134 | } 135 | n => return Err(BgpError::from_string(format!("Unknown afi code {:?}", n))), 136 | } 137 | let snpa_count = buf[curpos]; 138 | curpos += 1; 139 | for _ in 0..snpa_count { 140 | let snpa_len = buf[curpos] as usize; 141 | curpos += 1 + snpa_len; 142 | } 143 | let ap = BgpAddrs::decode_from(peer, afi, safi, &buf[curpos..])?; 144 | Ok(BgpMPUpdates { 145 | nexthop: nh, 146 | addrs: ap.0, 147 | }) 148 | } 149 | } 150 | 151 | impl std::fmt::Debug for BgpMPUpdates { 152 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 153 | f.debug_struct("BgpMPUpdates") 154 | .field("nexthop", &self.nexthop) 155 | .field("addrs", &self.addrs) 156 | .finish() 157 | } 158 | } 159 | impl std::fmt::Display for BgpMPUpdates { 160 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 161 | write!(f, "BgpMPUpdates ({:?} {:?})", self.nexthop, self.addrs) 162 | } 163 | } 164 | impl BgpAttr for BgpMPUpdates { 165 | fn attr(&self) -> BgpAttrParams { 166 | BgpAttrParams { 167 | typecode: 14, 168 | flags: 144, 169 | } 170 | } 171 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 172 | let afisafi = self.addrs.get_afi_safi(); 173 | setn_u16(afisafi.0, &mut buf[..2]); 174 | buf[2] = afisafi.1; 175 | let mut curpos: usize = 4; 176 | let nhl = match &self.nexthop { 177 | BgpAddr::None => 0, 178 | BgpAddr::V4(a) => encode_addrv4_to(a, &mut buf[curpos..])?, 179 | BgpAddr::V6(a) => encode_addrv6_to(a, &mut buf[curpos..])?, 180 | BgpAddr::V4RD(a) => a.encode_to(peer.peer_mode, &mut buf[curpos..])?, 181 | BgpAddr::V6RD(a) => a.encode_to(peer.peer_mode, &mut buf[curpos..])?, 182 | _ => return Err(BgpError::static_str("Invalid nexthop kind")), 183 | }; 184 | buf[3] = nhl as u8; 185 | curpos += nhl; 186 | buf[curpos] = 0; //snpa 187 | curpos += 1; 188 | let ps = self.addrs.encode_to(peer, &mut buf[curpos..])?; 189 | curpos += ps; 190 | Ok(curpos) 191 | } 192 | } 193 | 194 | /// BGP multiprotocol withdraws 195 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 196 | #[cfg(feature = "serialization")] 197 | #[derive(Serialize, Deserialize)] 198 | pub struct BgpMPWithdraws { 199 | /// NLRI 200 | pub addrs: BgpAddrs, 201 | } 202 | impl BgpMPWithdraws { 203 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 204 | let afi = getn_u16(buf); 205 | let safi = buf[2]; 206 | let a = BgpAddrs::decode_from(peer, afi, safi, &buf[3..])?; 207 | Ok(BgpMPWithdraws { addrs: a.0 }) 208 | } 209 | } 210 | impl std::fmt::Debug for BgpMPWithdraws { 211 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 212 | f.debug_struct("BgpMPWithdraws") 213 | .field("addrs", &self.addrs) 214 | .finish() 215 | } 216 | } 217 | impl std::fmt::Display for BgpMPWithdraws { 218 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 219 | write!(f, "BgpMPWithdraws ({:?})", self.addrs) 220 | } 221 | } 222 | impl BgpAttr for BgpMPWithdraws { 223 | fn attr(&self) -> BgpAttrParams { 224 | BgpAttrParams { 225 | typecode: 15, 226 | flags: 144, 227 | } 228 | } 229 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 230 | let afisafi = self.addrs.get_afi_safi(); 231 | setn_u16(afisafi.0, &mut buf[..2]); 232 | buf[2] = afisafi.1; 233 | let mut curpos: usize = 3; 234 | let ps = self.addrs.encode_to(peer, &mut buf[curpos..])?; 235 | curpos += ps; 236 | Ok(curpos) 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/message/attributes/nexthop.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP nexthop path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP nexthop 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | #[serde(transparent)] 20 | pub struct BgpNextHop { 21 | /// next hop itself 22 | pub value: std::net::IpAddr, 23 | } 24 | impl BgpNextHop { 25 | pub fn new(v: std::net::IpAddr) -> BgpNextHop { 26 | BgpNextHop { value: v } 27 | } 28 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 29 | if peer.peer_mode == BgpTransportMode::IPv6 && buf.len() >= 16 { 30 | return Ok(BgpNextHop { 31 | value: std::net::IpAddr::V6(decode_addrv6_from(buf)?), 32 | }); 33 | } 34 | if peer.peer_mode == BgpTransportMode::IPv4 && buf.len() >= 4 { 35 | return Ok(BgpNextHop { 36 | value: std::net::IpAddr::V4(decode_addrv4_from(buf)?), 37 | }); 38 | } 39 | Err(BgpError::static_str("Invalid nexthop length")) 40 | } 41 | } 42 | impl std::fmt::Debug for BgpNextHop { 43 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 44 | f.debug_struct("BgpNextHop") 45 | .field("value", &self.value) 46 | .finish() 47 | } 48 | } 49 | impl std::fmt::Display for BgpNextHop { 50 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 51 | write!(f, "NextHop {:?}", self.value) 52 | } 53 | } 54 | impl BgpAttr for BgpNextHop { 55 | fn attr(&self) -> BgpAttrParams { 56 | BgpAttrParams { 57 | typecode: 3, 58 | flags: 64, 59 | } 60 | } 61 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 62 | if let std::net::IpAddr::V6(v) = self.value { 63 | if peer.peer_mode == BgpTransportMode::IPv6 && buf.len() >= 16 { 64 | return encode_addrv6_to(&v, buf); 65 | } 66 | }; 67 | if let std::net::IpAddr::V4(v) = self.value { 68 | if peer.peer_mode == BgpTransportMode::IPv4 && buf.len() >= 4 { 69 | return encode_addrv4_to(&v, buf); 70 | } 71 | }; 72 | Err(BgpError::static_str("Invalid nexthop type")) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/message/attributes/origin.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP origin path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// BGP origin value 16 | #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub enum BgpAttrOrigin { 20 | Igp, 21 | Egp, 22 | Incomplete, 23 | } 24 | impl std::fmt::Display for BgpAttrOrigin { 25 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 26 | match self { 27 | BgpAttrOrigin::Igp => f.write_str("Igp"), 28 | BgpAttrOrigin::Egp => f.write_str("Egp"), 29 | BgpAttrOrigin::Incomplete => f.write_str("Incomplete"), 30 | } 31 | } 32 | } 33 | 34 | /// BGP origin path attribute 35 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 36 | #[cfg(feature = "serialization")] 37 | #[derive(Serialize, Deserialize)] 38 | #[serde(transparent)] 39 | pub struct BgpOrigin { 40 | pub value: BgpAttrOrigin, 41 | } 42 | impl BgpOrigin { 43 | pub fn new(v: BgpAttrOrigin) -> BgpOrigin { 44 | BgpOrigin { value: v } 45 | } 46 | pub fn decode_from(buf: &[u8]) -> Result { 47 | if buf.is_empty() { 48 | Err(BgpError::InsufficientBufferSize) 49 | } else { 50 | match buf[0] { 51 | 0 => Ok(BgpOrigin { 52 | value: BgpAttrOrigin::Igp, 53 | }), 54 | 1 => Ok(BgpOrigin { 55 | value: BgpAttrOrigin::Egp, 56 | }), 57 | 2 => Ok(BgpOrigin { 58 | value: BgpAttrOrigin::Incomplete, 59 | }), 60 | _ => Err(BgpError::static_str("Invalid value for BgpOrigin")), 61 | } 62 | } 63 | } 64 | } 65 | impl std::fmt::Debug for BgpOrigin { 66 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 67 | f.debug_struct("BgpOrigin") 68 | .field("value", &self.value) 69 | .finish() 70 | } 71 | } 72 | impl std::fmt::Display for BgpOrigin { 73 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 74 | match self.value { 75 | BgpAttrOrigin::Igp => { 76 | write!(f, "origin igp") 77 | } 78 | BgpAttrOrigin::Egp => { 79 | write!(f, "origin egp") 80 | } 81 | BgpAttrOrigin::Incomplete => { 82 | write!(f, "origin incomplete") 83 | } 84 | } 85 | } 86 | } 87 | 88 | impl BgpAttr for BgpOrigin { 89 | fn attr(&self) -> BgpAttrParams { 90 | BgpAttrParams { 91 | typecode: 1, 92 | flags: 64, 93 | } 94 | } 95 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 96 | if buf.is_empty() { 97 | Err(BgpError::InsufficientBufferSize) 98 | } else { 99 | match self.value { 100 | BgpAttrOrigin::Igp => { 101 | buf[0] = 0; 102 | Ok(1) 103 | } 104 | BgpAttrOrigin::Egp => { 105 | buf[0] = 1; 106 | Ok(1) 107 | } 108 | BgpAttrOrigin::Incomplete => { 109 | buf[0] = 2; 110 | Ok(1) 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/message/attributes/originatorid.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP originator id path attribute 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | use std::net::IpAddr; 15 | 16 | /// BGP originator id path attribute 17 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 18 | #[cfg(feature = "serialization")] 19 | #[derive(Serialize, Deserialize)] 20 | #[serde(transparent)] 21 | pub struct BgpOriginatorID { 22 | pub value: IpAddr, 23 | } 24 | impl BgpOriginatorID { 25 | pub fn new(o: IpAddr) -> BgpOriginatorID { 26 | BgpOriginatorID { value: o } 27 | } 28 | pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { 29 | match peer.peer_mode { 30 | BgpTransportMode::IPv4 => Ok(BgpOriginatorID { 31 | value: decode_addr_from(&buf[..4])?, 32 | }), 33 | BgpTransportMode::IPv6 => Ok(BgpOriginatorID { 34 | value: if buf.len() < 16 { 35 | decode_addr_from(&buf[..4])? 36 | } else { 37 | decode_addr_from(&buf[..16])? 38 | }, 39 | }), 40 | } 41 | } 42 | } 43 | impl std::fmt::Debug for BgpOriginatorID { 44 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 45 | f.debug_struct("BgpOriginatorID") 46 | .field("value", &self.value) 47 | .finish() 48 | } 49 | } 50 | impl std::fmt::Display for BgpOriginatorID { 51 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 52 | write!(f, "BgpOriginatorID {}", self.value) 53 | } 54 | } 55 | impl BgpAttr for BgpOriginatorID { 56 | fn attr(&self) -> BgpAttrParams { 57 | BgpAttrParams { 58 | typecode: 9, 59 | flags: 0x80, 60 | } 61 | } 62 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 63 | match peer.peer_mode { 64 | BgpTransportMode::IPv4 => { 65 | if let IpAddr::V4(ref a) = self.value { 66 | encode_addrv4_to(a, buf) 67 | } else { 68 | Err(BgpError::static_str("Invalid originatorid kind")) 69 | } 70 | } 71 | BgpTransportMode::IPv6 => { 72 | if let IpAddr::V6(ref a) = self.value { 73 | encode_addrv6_to(a, buf) 74 | } else { 75 | Err(BgpError::static_str("Invalid originatorid kind")) 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/message/attributes/pmsitunnelattr.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP PMSI tunnel path attribute - used for MVPN and EVPN 10 | 11 | use crate::afi::{BgpItem, MplsLabels}; 12 | use crate::message::attributes::*; 13 | #[cfg(feature = "serialization")] 14 | use serde::{Deserialize, Serialize}; 15 | 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub struct BgpPMSITaRSVP { 20 | pub ext_tunnel_id: std::net::Ipv4Addr, 21 | pub reserved: u16, 22 | pub tunnel_id: u16, 23 | pub p2mp_id: std::net::Ipv4Addr, 24 | } 25 | impl std::fmt::Display for BgpPMSITaRSVP { 26 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 27 | write!( 28 | f, 29 | "RSVP-TE P2MP LSP:{}:{}:{}:{}", 30 | self.ext_tunnel_id, self.reserved, self.tunnel_id, self.p2mp_id 31 | ) 32 | } 33 | } 34 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 35 | #[cfg(feature = "serialization")] 36 | #[derive(Serialize, Deserialize)] 37 | #[serde(transparent)] 38 | pub struct BgpPMSITaIngressRepl { 39 | pub endpoint: std::net::Ipv4Addr, 40 | } 41 | impl std::fmt::Display for BgpPMSITaIngressRepl { 42 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 43 | write!(f, "Ingress replication:{}", self.endpoint) 44 | } 45 | } 46 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 47 | #[cfg(feature = "serialization")] 48 | #[derive(Serialize, Deserialize)] 49 | pub struct BgpPMSITaMLDP { 50 | pub rootnode: std::net::IpAddr, 51 | pub opaque: Vec, 52 | } 53 | impl std::fmt::Display for BgpPMSITaMLDP { 54 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 55 | write!(f, "mLDP P2MP LSP:{}", self.rootnode) 56 | } 57 | } 58 | /// PMSI tunnel attribute 59 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] 60 | #[cfg(feature = "serialization")] 61 | #[derive(Serialize, Deserialize)] 62 | pub enum BgpPMSITunnelAttr { 63 | None, 64 | RSVPTe(BgpPMSITaRSVP), 65 | IngressRepl(BgpPMSITaIngressRepl), 66 | MLDP(BgpPMSITaMLDP), 67 | } 68 | impl std::fmt::Display for BgpPMSITunnelAttr { 69 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 70 | match self { 71 | BgpPMSITunnelAttr::None => "".fmt(f), 72 | BgpPMSITunnelAttr::RSVPTe(r) => r.fmt(f), 73 | BgpPMSITunnelAttr::IngressRepl(r) => r.fmt(f), 74 | BgpPMSITunnelAttr::MLDP(r) => r.fmt(f), 75 | } 76 | } 77 | } 78 | 79 | /// BGP Path attribute for PMSI tunnel RFC6514 80 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 81 | #[cfg(feature = "serialization")] 82 | #[derive(Serialize, Deserialize)] 83 | pub struct BgpPMSITunnel { 84 | pub flags: u8, 85 | pub tunnel_type: u8, 86 | pub label: MplsLabels, 87 | pub tunnel_attribute: BgpPMSITunnelAttr, 88 | } 89 | /* 90 | tunnel_type 91 | + 0 - No tunnel information present 92 | + 1 - RSVP-TE P2MP LSP 93 | + 2 - mLDP P2MP LSP 94 | + 3 - PIM-SSM Tree 95 | + 4 - PIM-SM Tree 96 | + 5 - BIDIR-PIM Tree 97 | + 6 - Ingress Replication 98 | + 7 - mLDP MP2MP LSP 99 | */ 100 | impl BgpPMSITunnel { 101 | pub fn decode_from(_peer: &BgpSessionParams, buf: &[u8]) -> Result { 102 | if buf.len() < 5 { 103 | return Err(BgpError::static_str("Invalid PMSI buffer length")); 104 | } 105 | let lbls = MplsLabels::extract_bits_from(24, &buf[2..])?; 106 | let curpos = 2 + lbls.1; 107 | Ok(BgpPMSITunnel { 108 | flags: buf[0], 109 | tunnel_type: buf[1], 110 | label: lbls.0, 111 | tunnel_attribute: match buf[1] { 112 | 0 => BgpPMSITunnelAttr::None, 113 | 1 => 114 | //RSVP-TE P2MP LSP 115 | { 116 | BgpPMSITunnelAttr::RSVPTe(BgpPMSITaRSVP { 117 | ext_tunnel_id: std::net::Ipv4Addr::new( 118 | buf[curpos], 119 | buf[curpos + 1], 120 | buf[curpos + 2], 121 | buf[curpos + 3], 122 | ), 123 | reserved: getn_u16(&buf[curpos + 4..]), 124 | tunnel_id: getn_u16(&buf[curpos + 6..]), 125 | p2mp_id: std::net::Ipv4Addr::new( 126 | buf[curpos + 8], 127 | buf[curpos + 9], 128 | buf[curpos + 10], 129 | buf[curpos + 11], 130 | ), 131 | }) 132 | } 133 | 2 => { 134 | if buf[5] != 6 { 135 | return Err(BgpError::from_string(format!( 136 | "Unknown PMSI tunnel type mLDP p2mp: {}", 137 | buf[5] 138 | ))); 139 | } 140 | if buf.len() < 16 { 141 | return Err(BgpError::from_string(format!( 142 | "PMSI tunnel type mLDP p2mp too short: {}", 143 | buf.len() 144 | ))); 145 | } 146 | if getn_u16(&buf[6..8]) != 1 { 147 | return Err(BgpError::Static("Invalid root node address family")); 148 | } 149 | if buf[8] != 4 { 150 | return Err(BgpError::Static("Invalid root node address length")); 151 | } 152 | let rootnode = decode_addr_from(&buf[9..13])?; 153 | let opaquelen = getn_u16(&buf[13..15]) as usize; 154 | if buf.len() < (15 + opaquelen) { 155 | return Err(BgpError::from_string(format!( 156 | "PMSI tunnel type mLDP p2mp too short: {} < 15+{}", 157 | buf.len(), 158 | opaquelen 159 | ))); 160 | } 161 | BgpPMSITunnelAttr::MLDP(BgpPMSITaMLDP { 162 | rootnode, 163 | opaque: buf[15..(15 + opaquelen)].to_vec(), 164 | }) 165 | } 166 | 6 => 167 | //Ingress replication 168 | { 169 | BgpPMSITunnelAttr::IngressRepl(BgpPMSITaIngressRepl { 170 | endpoint: std::net::Ipv4Addr::new( 171 | buf[curpos], 172 | buf[curpos + 1], 173 | buf[curpos + 2], 174 | buf[curpos + 3], 175 | ), 176 | }) 177 | } 178 | _ => { 179 | return Err(BgpError::from_string(format!( 180 | "Unknown PMSI tunnel type: {}, flags {}, buf: {:?}", 181 | buf[1], buf[0], buf 182 | ))); 183 | } 184 | }, 185 | }) 186 | } 187 | } 188 | impl std::fmt::Debug for BgpPMSITunnel { 189 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 190 | f.debug_struct("BgpPMSITunnel") 191 | .field("flags", &self.flags) 192 | .field("tunnel_type", &self.tunnel_type) 193 | .field("label", &self.label) 194 | .field("tunnel_attribute", &self.tunnel_attribute) 195 | .finish() 196 | } 197 | } 198 | impl std::fmt::Display for BgpPMSITunnel { 199 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 200 | write!( 201 | f, 202 | "BgpPMSITunnel flags={} type={} label={} attribute={}", 203 | self.flags, self.tunnel_type, self.label, self.tunnel_attribute 204 | ) 205 | } 206 | } 207 | impl BgpAttr for BgpPMSITunnel { 208 | fn attr(&self) -> BgpAttrParams { 209 | BgpAttrParams { 210 | typecode: 22, 211 | flags: 192, 212 | } 213 | } 214 | fn encode_to(&self, _peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { 215 | unimplemented!(); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/message/attributes/unknown.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! BGP unsupported path attributes 10 | 11 | use crate::message::attributes::*; 12 | #[cfg(feature = "serialization")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// Unsupported BGP path attribute 16 | #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg(feature = "serialization")] 18 | #[derive(Serialize, Deserialize)] 19 | pub struct BgpAttrUnknown { 20 | /// PA typecode&flags 21 | pub params: BgpAttrParams, 22 | /// byte code "meat" 23 | pub value: Vec, 24 | } 25 | impl BgpAttrUnknown { 26 | pub fn new(tc: u8, flg: u8) -> BgpAttrUnknown { 27 | BgpAttrUnknown { 28 | params: BgpAttrParams { 29 | typecode: tc, 30 | flags: flg, 31 | }, 32 | value: Vec::new(), 33 | } 34 | } 35 | pub fn decode_from(tc: u8, flg: u8, buf: &[u8]) -> Result { 36 | let mut ret = BgpAttrUnknown { 37 | params: BgpAttrParams { 38 | typecode: tc, 39 | flags: flg, 40 | }, 41 | value: Vec::new(), 42 | }; 43 | ret.value.resize(buf.len(), 0); 44 | ret.value.copy_from_slice(buf); 45 | Ok(ret) 46 | } 47 | } 48 | impl std::fmt::Debug for BgpAttrUnknown { 49 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 50 | f.debug_struct("BgpAttrUnknown") 51 | .field("params", &self.params) 52 | .field("value", &self.value) 53 | .finish() 54 | } 55 | } 56 | impl std::fmt::Display for BgpAttrUnknown { 57 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 58 | write!( 59 | f, 60 | "PA unknown(tc={:?},flg={:?} {:?})", 61 | self.params.typecode, self.params.flags, self.value 62 | ) 63 | } 64 | } 65 | impl BgpAttr for BgpAttrUnknown { 66 | fn attr(&self) -> BgpAttrParams { 67 | BgpAttrParams { 68 | typecode: self.params.typecode, 69 | flags: self.params.flags, 70 | } 71 | } 72 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 73 | buf[0..self.value.len()].clone_from_slice(self.value.as_slice()); 74 | Ok(self.value.len()) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/message/keepalive.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::*; 10 | 11 | /// BGP keepalive message 12 | #[derive(Debug)] 13 | pub struct BgpKeepaliveMessage {} 14 | 15 | impl BgpMessage for BgpKeepaliveMessage { 16 | fn decode_from(&mut self, _peer: &BgpSessionParams, _buf: &[u8]) -> Result<(), BgpError> { 17 | Ok(()) 18 | } 19 | fn encode_to(&self, _peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { 20 | Ok(0) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/message/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module contains BGP messages 10 | 11 | use crate::error::*; 12 | use crate::*; 13 | 14 | pub mod attributes; 15 | pub mod keepalive; 16 | pub mod notification; 17 | pub mod open; 18 | pub use open::*; 19 | pub mod update; 20 | pub use update::*; 21 | 22 | /// trait BgpMessage represents BGP protocol message 23 | pub trait BgpMessage { 24 | fn decode_from(&mut self, peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError>; 25 | fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result; 26 | } 27 | 28 | /// Bgp message type: open, update, notification or keepalive. 29 | #[derive(Debug, Clone, PartialEq, Eq)] 30 | pub enum BgpMessageType { 31 | Open, 32 | Update, 33 | Notification, 34 | Keepalive, 35 | } 36 | 37 | impl BgpMessageType { 38 | /// decodes BGP message type from byte code 39 | pub fn decode_from(code: u8) -> Result { 40 | match code { 41 | 1 => Ok(BgpMessageType::Open), 42 | 2 => Ok(BgpMessageType::Update), 43 | 3 => Ok(BgpMessageType::Notification), 44 | 4 => Ok(BgpMessageType::Keepalive), 45 | _ => Err(BgpError::static_str("Invalid message type")), 46 | } 47 | } 48 | /// encodes BGP message type into the byte code 49 | pub fn encode(&self) -> u8 { 50 | match self { 51 | BgpMessageType::Open => 1, 52 | BgpMessageType::Update => 2, 53 | BgpMessageType::Notification => 3, 54 | BgpMessageType::Keepalive => 4, 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/message/notification.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::{BgpError, BgpMessage, BgpSessionParams}; 10 | 11 | /// BGP notification message 12 | pub struct BgpNotificationMessage { 13 | /// error code 14 | pub error_code: u8, 15 | /// error sub-code 16 | pub error_subcode: u8, 17 | /// extra data 18 | pub data: u16, 19 | } 20 | impl BgpNotificationMessage { 21 | /// constructs new empty message 22 | pub fn new() -> BgpNotificationMessage { 23 | BgpNotificationMessage { 24 | error_code: 0, 25 | error_subcode: 0, 26 | data: 0, 27 | } 28 | } 29 | /// returns human-friendly error interpretation. 30 | pub fn error_text(&self) -> String { 31 | match self.error_code { 32 | 1 => { 33 | String::from("Message Header Error: ") 34 | + (match self.error_subcode { 35 | 1 => String::from("Connection not synchronized"), 36 | 2 => String::from("Bad Message Length"), 37 | 3 => String::from("Bad Message Type"), 38 | n => String::from(" subcode ") + n.to_string().as_str(), 39 | }) 40 | .as_str() 41 | } 42 | 2 => { 43 | String::from("OPEN Message Error: ") 44 | + (match self.error_subcode { 45 | 1 => String::from("Unsupported Version Number"), 46 | 2 => String::from("Bad Peer AS"), 47 | 3 => String::from("Bad BGP Identifier"), 48 | 4 => String::from("Unsupported Optional Parameter"), 49 | 5 => String::from("Deprecated(5)"), 50 | 6 => String::from("Unacceptable Hold Time"), 51 | 7 => String::from("Unsupported capability"), 52 | n => String::from(" subcode ") + n.to_string().as_str(), 53 | }) 54 | .as_str() 55 | } 56 | 3 => { 57 | String::from("Update Message Error: ") 58 | + (match self.error_subcode { 59 | 1 => String::from("Malformed Attribute List"), 60 | 2 => String::from("Unrecognized Well-known Attribute"), 61 | 3 => String::from("Missing Well-known Attribute"), 62 | 4 => String::from("Attribute Flags Error"), 63 | 5 => String::from("Attribute Length Error"), 64 | 6 => String::from("Invalid ORIGIN Attribute"), 65 | 7 => String::from("Deprecated(7)"), 66 | 8 => String::from("Invalid NEXT_HOP Attribute"), 67 | 9 => String::from("Optional Attribute Error"), 68 | 10 => String::from("Invalid Network Field"), 69 | 11 => String::from("Malformed AS_PATH"), 70 | n => String::from(" subcode ") + n.to_string().as_str(), 71 | }) 72 | .as_str() 73 | } 74 | 4 => { 75 | String::from("Hold Timer Expired") 76 | + (if self.error_subcode != 0 { 77 | String::from(" subcode ") + self.error_subcode.to_string().as_str() 78 | } else { 79 | String::from("(0)") 80 | }) 81 | .as_str() 82 | } 83 | 5 => { 84 | String::from("Finite State Machine Error") 85 | + (if self.error_subcode != 0 { 86 | String::from(" subcode ") + self.error_subcode.to_string().as_str() 87 | } else { 88 | String::from("(0)") 89 | }) 90 | .as_str() 91 | } 92 | 6 => { 93 | String::from("Cease") 94 | + (if self.error_subcode != 0 { 95 | String::from(" subcode ") + self.error_subcode.to_string().as_str() 96 | } else { 97 | String::from("(0)") 98 | }) 99 | .as_str() 100 | } 101 | n => { 102 | String::from("Unknown code ") 103 | + n.to_string().as_str() 104 | + " subcode " 105 | + self.error_subcode.to_string().as_str() 106 | } 107 | } 108 | } 109 | } 110 | impl std::fmt::Debug for BgpNotificationMessage { 111 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 112 | f.debug_struct("BgpNotificationMessage") 113 | .field("error_code", &self.error_code) 114 | .field("error_subcode", &self.error_subcode) 115 | .field("data", &self.data) 116 | .finish() 117 | } 118 | } 119 | impl std::fmt::Display for BgpNotificationMessage { 120 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 121 | write!( 122 | f, 123 | "BgpNotificationMessage {:?} code={:?} subcode={:?} data={:?})", 124 | self.error_text(), 125 | self.error_code, 126 | self.error_subcode, 127 | self.data 128 | ) 129 | } 130 | } 131 | impl Default for BgpNotificationMessage { 132 | fn default() -> Self { 133 | Self::new() 134 | } 135 | } 136 | impl BgpMessage for BgpNotificationMessage { 137 | fn decode_from(&mut self, _peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError> { 138 | if buf.len() < 2 { 139 | return Err(BgpError::static_str("Invalid notification message length")); 140 | } 141 | self.error_code = buf[0]; 142 | self.error_subcode = buf[1]; 143 | if buf.len() == 3 { 144 | self.data = buf[2] as u16; 145 | } 146 | if buf.len() > 3 { 147 | self.data = ((buf[2] as u16) << 8) | (buf[3] as u16); 148 | } 149 | Ok(()) 150 | } 151 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 152 | if buf.len() < 4 { 153 | return Err(BgpError::static_str("Invalid notification message length")); 154 | } 155 | buf[0] = self.error_code; 156 | buf[1] = self.error_subcode; 157 | buf[2] = (self.data >> 8) as u8; 158 | buf[3] = (self.data & 0xff) as u8; 159 | Ok(4) 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/message/open.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::{ntoh16, slice, slice_mut, BgpCapability, BgpError, BgpMessage, BgpSessionParams}; 10 | use std::vec::Vec; 11 | /// BGP open message 12 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 13 | pub struct BgpOpenMessage { 14 | /// Autonomous system number 15 | pub as_num: u32, 16 | /// Hold time in seconds 17 | pub hold_time: u16, 18 | /// router Id 19 | pub router_id: std::net::Ipv4Addr, 20 | /// Capability set 21 | pub caps: Vec, 22 | } 23 | 24 | #[repr(C, packed)] 25 | struct BgpOpenHead { 26 | as_num: u16, 27 | hold_time: u16, 28 | routerid: [u8; 4], 29 | caplen: u8, 30 | } 31 | 32 | impl BgpMessage for BgpOpenMessage { 33 | fn decode_from(&mut self, _peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError> { 34 | if buf.len() < 10 { 35 | return Err(BgpError::InsufficientBufferSize); 36 | } 37 | if buf[0] != 4 { 38 | return Err(BgpError::static_str("Invalid BGP version <> 4")); 39 | } 40 | let ptr: *const u8 = slice(buf, 1, buf.len())?.as_ptr(); 41 | let ptr: *const BgpOpenHead = ptr as *const BgpOpenHead; 42 | let ptr: &BgpOpenHead = unsafe { &*ptr }; 43 | self.as_num = ntoh16(ptr.as_num) as u32; 44 | self.hold_time = ntoh16(ptr.hold_time); 45 | self.router_id = std::net::Ipv4Addr::new( 46 | ptr.routerid[0], 47 | ptr.routerid[1], 48 | ptr.routerid[2], 49 | ptr.routerid[3], 50 | ); 51 | self.caps.clear(); 52 | let mut pos: usize = 10; 53 | while pos + 1 < buf.len() { 54 | if buf[pos] != 2 { 55 | return Err(BgpError::from_string(format!( 56 | "Invalid optional parameter in BGP open message {:?}!", 57 | buf[pos] 58 | ))); 59 | } 60 | let mut optlen = buf[pos + 1] as usize; 61 | pos += 2; 62 | while optlen > 0 { 63 | let maybe_cap = BgpCapability::from_buffer(slice(buf, pos, pos + optlen)?)?; 64 | optlen -= maybe_cap.1; 65 | pos += maybe_cap.1; 66 | match maybe_cap.0 { 67 | Ok(cap) => self.caps.push(cap), 68 | Err((captype, data)) => log::trace!( 69 | "ignoring unknown capability code {} data {:x?}", 70 | captype, 71 | data 72 | ), 73 | } 74 | } 75 | } 76 | Ok(()) 77 | } 78 | fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { 79 | if buf.len() < 10 { 80 | return Err(BgpError::InsufficientBufferSize); 81 | } 82 | let ptr: *mut u8 = slice_mut(buf, 1, buf.len())?.as_mut_ptr(); 83 | let ptr: *mut BgpOpenHead = ptr as *mut BgpOpenHead; 84 | let ptr: &mut BgpOpenHead = unsafe { &mut *ptr }; 85 | buf[0] = 4; 86 | ptr.as_num = ntoh16(if self.as_num < 65536 { 87 | self.as_num as u16 88 | } else { 89 | 23456 90 | }); 91 | ptr.hold_time = ntoh16(self.hold_time); 92 | ptr.routerid = self.router_id.octets(); 93 | ptr.caplen = self 94 | .caps 95 | .iter() 96 | .fold(0u32, |sum, i| sum + (i.bytes_len() as u32) + 2) as u8; 97 | let mut pos: usize = 10; 98 | for cp in self.caps.iter() { 99 | let caplen = cp.bytes_len(); 100 | buf[pos] = 2; //capability 101 | buf[pos + 1] = caplen as u8; 102 | cp.fill_buffer(slice_mut(buf, pos + 2, caplen + pos + 2)?)?; 103 | pos += 2 + caplen; 104 | } 105 | Ok(pos) 106 | } 107 | } 108 | impl BgpOpenMessage { 109 | pub fn new() -> BgpOpenMessage { 110 | BgpOpenMessage { 111 | as_num: 0, 112 | hold_time: 180, 113 | router_id: std::net::Ipv4Addr::new(127, 0, 0, 1), 114 | caps: Vec::new(), 115 | } 116 | } 117 | } 118 | impl Default for BgpOpenMessage { 119 | fn default() -> Self { 120 | Self::new() 121 | } 122 | } 123 | 124 | #[cfg(test)] 125 | mod tests { 126 | use super::*; 127 | use crate::BgpTransportMode; 128 | 129 | #[test] 130 | fn test_good_open() { 131 | // Setup 132 | let mut buf = vec![0_u8; 4096]; 133 | let caps = vec![ 134 | BgpCapability::SafiIPv4u, 135 | BgpCapability::CapRR, 136 | BgpCapability::CapASN32(65450), 137 | ]; 138 | let params = BgpSessionParams::new( 139 | 65001, 140 | 30, 141 | BgpTransportMode::IPv4, 142 | "10.0.0.1".parse().unwrap(), 143 | caps.clone(), 144 | ); 145 | let msg = BgpOpenMessage { 146 | as_num: 200, 147 | router_id: "10.0.0.1".parse().unwrap(), 148 | caps, 149 | hold_time: 180, 150 | }; 151 | 152 | let encode = msg.encode_to(¶ms, &mut buf); 153 | assert!(encode.is_ok()); 154 | 155 | let mut decode_msg = BgpOpenMessage::new(); 156 | 157 | // Trucate to fit encoded message length 158 | buf.truncate(encode.unwrap()); 159 | 160 | let decode = decode_msg.decode_from(¶ms, &buf); 161 | match decode { 162 | Ok(_) => { 163 | assert_eq!(decode_msg.as_num, msg.as_num); 164 | assert_eq!(decode_msg.hold_time, msg.hold_time); 165 | assert_eq!(decode_msg.router_id, msg.router_id,); 166 | assert_eq!(decode_msg.caps.len(), msg.caps.len()); 167 | for c in decode_msg.caps.iter() { 168 | assert!(msg.caps.contains(c)); 169 | } 170 | } 171 | _ => panic!("incorrect decode: {:?}", decode), 172 | } 173 | } 174 | 175 | #[test] 176 | fn test_concatenated_open() { 177 | // Setup 178 | let mut buf = vec![0_u8; 4096]; 179 | let caps = vec![ 180 | BgpCapability::SafiIPv4u, 181 | BgpCapability::CapRR, 182 | BgpCapability::CapASN32(65450), 183 | ]; 184 | let params = BgpSessionParams::new( 185 | 65001, 186 | 30, 187 | BgpTransportMode::IPv4, 188 | "10.0.0.1".parse().unwrap(), 189 | caps.clone(), 190 | ); 191 | let msg = BgpOpenMessage { 192 | as_num: 200, 193 | router_id: "10.0.0.1".parse().unwrap(), 194 | caps, 195 | hold_time: 180, 196 | }; 197 | 198 | let encode = msg.encode_to(¶ms, &mut buf); 199 | assert!(encode.is_ok()); 200 | 201 | let encode = msg.encode_to(¶ms, &mut buf); 202 | assert!(encode.is_ok()); 203 | 204 | // Trucate to fit encoded message length 205 | buf.truncate(encode.unwrap()); 206 | 207 | let mut decode_msg = BgpOpenMessage::new(); 208 | let decode = decode_msg.decode_from(¶ms, &buf); 209 | match decode { 210 | Ok(_) => { 211 | assert_eq!(decode_msg.as_num, msg.as_num); 212 | assert_eq!(decode_msg.hold_time, msg.hold_time); 213 | assert_eq!(decode_msg.router_id, msg.router_id); 214 | assert_eq!(decode_msg.caps.len(), msg.caps.len()); 215 | for c in decode_msg.caps.iter() { 216 | assert!(params.caps.contains(c), "caps.contains(): {:?}", c); 217 | } 218 | } 219 | _ => panic!("incorrect decode: {:?}", decode), 220 | } 221 | 222 | let mut decode_msg = BgpOpenMessage::new(); 223 | let decode = decode_msg.decode_from(¶ms, &buf); 224 | match decode { 225 | Ok(_) => { 226 | assert_eq!(decode_msg.as_num, msg.as_num); 227 | assert_eq!(decode_msg.hold_time, msg.hold_time); 228 | assert_eq!(decode_msg.router_id, msg.router_id); 229 | assert_eq!(decode_msg.caps.len(), msg.caps.len()); 230 | for c in decode_msg.caps.iter() { 231 | assert!(params.caps.contains(c), "caps.contains(): {:?}", c); 232 | } 233 | } 234 | _ => panic!("incorrect decode: {:?}", decode), 235 | } 236 | } 237 | 238 | #[test] 239 | fn test_bad_open_decode_length() { 240 | // Setup 241 | let mut buf = vec![0_u8; 4096]; 242 | let caps = vec![ 243 | BgpCapability::SafiIPv4u, 244 | BgpCapability::CapRR, 245 | BgpCapability::CapASN32(65450), 246 | ]; 247 | let params = BgpSessionParams::new( 248 | 65001, 249 | 30, 250 | BgpTransportMode::IPv4, 251 | "10.0.0.1".parse().unwrap(), 252 | caps.clone(), 253 | ); 254 | let mut msg = BgpOpenMessage { 255 | as_num: 200, 256 | router_id: "10.0.0.1".parse().unwrap(), 257 | caps, 258 | hold_time: 180, 259 | }; 260 | 261 | let encode = msg.encode_to(¶ms, &mut buf); 262 | assert!(encode.is_ok()); 263 | 264 | // Truncate encoded cap data 265 | let truncate_amount = 3; 266 | buf.truncate(encode.unwrap() - truncate_amount as usize); 267 | let decode = msg.decode_from(¶ms, &buf); 268 | assert!(matches!(decode, Err(BgpError::InsufficientBufferSize))); 269 | } 270 | 271 | #[test] 272 | fn test_bad_open_bgp_version() { 273 | // Setup 274 | let mut buf = vec![0_u8; 4096]; 275 | let caps = vec![ 276 | BgpCapability::SafiIPv4u, 277 | BgpCapability::CapRR, 278 | BgpCapability::CapASN32(65450), 279 | ]; 280 | let params = BgpSessionParams::new( 281 | 65001, 282 | 30, 283 | BgpTransportMode::IPv4, 284 | "10.0.0.1".parse().unwrap(), 285 | caps.clone(), 286 | ); 287 | let msg = BgpOpenMessage { 288 | as_num: 200, 289 | router_id: "10.0.0.1".parse().unwrap(), 290 | caps, 291 | hold_time: 180, 292 | }; 293 | 294 | let encode = msg.encode_to(¶ms, &mut buf); 295 | assert!(encode.is_ok()); 296 | 297 | // Set bgp version to be 3 298 | buf[0] = 3; 299 | 300 | let mut decode_msg = BgpOpenMessage::new(); 301 | let decode = decode_msg.decode_from(¶ms, &buf); 302 | assert!(matches!( 303 | decode, 304 | Err(BgpError::Static("Invalid BGP version <> 4")) 305 | )); 306 | } 307 | 308 | #[test] 309 | fn test_bad_open_decode_empty() { 310 | // Setup 311 | let buf = vec![0_u8; 0]; 312 | let caps = vec![ 313 | BgpCapability::SafiIPv4u, 314 | BgpCapability::CapRR, 315 | BgpCapability::CapASN32(65450), 316 | ]; 317 | let params = BgpSessionParams::new( 318 | 65001, 319 | 30, 320 | BgpTransportMode::IPv4, 321 | "10.0.0.1".parse().unwrap(), 322 | caps, 323 | ); 324 | 325 | let mut decode_msg = BgpOpenMessage::new(); 326 | let decode = decode_msg.decode_from(¶ms, &buf); 327 | assert!(matches!(decode, Err(BgpError::InsufficientBufferSize))); 328 | } 329 | 330 | #[test] 331 | fn test_bad_open_missing_optlen() { 332 | // Setup 333 | let mut buf = vec![0_u8; 4096]; 334 | let caps = vec![ 335 | BgpCapability::SafiIPv4u, 336 | BgpCapability::CapRR, 337 | BgpCapability::CapASN32(65450), 338 | ]; 339 | let params = BgpSessionParams::new( 340 | 65001, 341 | 30, 342 | BgpTransportMode::IPv4, 343 | "10.0.0.1".parse().unwrap(), 344 | caps.clone(), 345 | ); 346 | let msg = BgpOpenMessage { 347 | as_num: 200, 348 | router_id: "10.0.0.1".parse().unwrap(), 349 | caps, 350 | hold_time: 180, 351 | }; 352 | 353 | let encode = msg.encode_to(¶ms, &mut buf); 354 | assert!(encode.is_ok()); 355 | 356 | // Truncate to remove optlen 357 | buf.truncate(10_usize); 358 | 359 | let mut decode_msg = BgpOpenMessage::new(); 360 | let decode = decode_msg.decode_from(¶ms, &buf); 361 | assert!(decode.is_ok()); 362 | } 363 | 364 | #[test] 365 | fn test_bad_open_encode_empty() { 366 | // Setup 367 | let mut buf = vec![0_u8; 0]; 368 | let caps = vec![ 369 | BgpCapability::SafiIPv4u, 370 | BgpCapability::CapRR, 371 | BgpCapability::CapASN32(65450), 372 | ]; 373 | let params = BgpSessionParams::new( 374 | 65001, 375 | 30, 376 | BgpTransportMode::IPv4, 377 | "10.0.0.1".parse().unwrap(), 378 | caps.clone(), 379 | ); 380 | let msg = BgpOpenMessage { 381 | as_num: 200, 382 | router_id: "10.0.0.1".parse().unwrap(), 383 | caps, 384 | hold_time: 180, 385 | }; 386 | 387 | let encode = msg.encode_to(¶ms, &mut buf); 388 | assert!(matches!(encode, Err(BgpError::InsufficientBufferSize))); 389 | } 390 | 391 | #[test] 392 | fn test_bad_open_encode_length() { 393 | // Setup 394 | let mut buf = vec![0_u8; 20]; 395 | let caps = vec![ 396 | BgpCapability::SafiIPv4u, 397 | BgpCapability::CapRR, 398 | BgpCapability::CapASN32(65450), 399 | ]; 400 | let params = BgpSessionParams::new( 401 | 65001, 402 | 30, 403 | BgpTransportMode::IPv4, 404 | "10.0.0.1".parse().unwrap(), 405 | caps.clone(), 406 | ); 407 | let msg = BgpOpenMessage { 408 | as_num: 200, 409 | router_id: "10.0.0.1".parse().unwrap(), 410 | caps, 411 | hold_time: 180, 412 | }; 413 | 414 | let encode = msg.encode_to(¶ms, &mut buf); 415 | assert!(matches!(encode, Err(BgpError::InsufficientBufferSize))); 416 | } 417 | } 418 | -------------------------------------------------------------------------------- /src/prelude.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Convenience re-export of common members 10 | //! 11 | //! Like the standard library's prelude, this module simplifies importing of 12 | //! common items. Unlike the standard prelude, the contents of this module must 13 | //! be imported manually: 14 | //! 15 | //! ``` 16 | //! use zettabgp::prelude::*; 17 | //! ``` 18 | 19 | pub use crate::afi::evpn::*; 20 | pub use crate::afi::flowspec::*; 21 | pub use crate::afi::ipv4::*; 22 | pub use crate::afi::ipv6::*; 23 | pub use crate::afi::mvpn::*; 24 | pub use crate::afi::vpls::*; 25 | pub use crate::afi::*; 26 | pub use crate::error::*; 27 | pub use crate::util::*; 28 | pub use crate::*; 29 | 30 | pub use crate::message::keepalive::*; 31 | pub use crate::message::notification::*; 32 | pub use crate::message::open::*; 33 | pub use crate::message::update::*; 34 | pub use crate::message::*; 35 | pub use crate::BgpMessage; 36 | 37 | pub use crate::message::attributes::aggregatoras::*; 38 | pub use crate::message::attributes::aspath::*; 39 | pub use crate::message::attributes::atomicaggregate::*; 40 | pub use crate::message::attributes::attrset::*; 41 | pub use crate::message::attributes::clusterlist::*; 42 | pub use crate::message::attributes::community::*; 43 | pub use crate::message::attributes::extcommunity::*; 44 | pub use crate::message::attributes::localpref::*; 45 | pub use crate::message::attributes::med::*; 46 | pub use crate::message::attributes::multiproto::*; 47 | pub use crate::message::attributes::nexthop::*; 48 | pub use crate::message::attributes::origin::*; 49 | pub use crate::message::attributes::originatorid::*; 50 | pub use crate::message::attributes::pmsitunnelattr::*; 51 | pub use crate::message::attributes::unknown::*; 52 | pub use crate::message::attributes::*; 53 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Vladimir Melnikov. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module contains some internal utilities 10 | 11 | use crate::error::BgpError; 12 | 13 | /// Gets ipv4 address from the buffer. 14 | pub fn decode_addrv4_from(buf: &[u8]) -> Result { 15 | if buf.len() < 4 { 16 | return Err(BgpError::static_str("Invalid addrv4 length")); 17 | } 18 | Ok(std::net::Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])) 19 | } 20 | /// Stores ipv4 address into the buffer. 21 | pub fn encode_addrv4_to(addr: &std::net::Ipv4Addr, buf: &mut [u8]) -> Result { 22 | if buf.len() < 4 { 23 | return Err(BgpError::static_str("Invalid addrv4 length")); 24 | } 25 | buf[0..4].clone_from_slice(&addr.octets()); 26 | Ok(4) 27 | } 28 | /// Gets ipv6 address from the buffer. 29 | pub fn decode_addrv6_from(buf: &[u8]) -> Result { 30 | if buf.len() < 16 { 31 | return Err(BgpError::static_str("Invalid addrv6 length")); 32 | } 33 | Ok(std::net::Ipv6Addr::new( 34 | getn_u16(&buf[0..2]), 35 | getn_u16(&buf[2..4]), 36 | getn_u16(&buf[4..6]), 37 | getn_u16(&buf[6..8]), 38 | getn_u16(&buf[8..10]), 39 | getn_u16(&buf[10..12]), 40 | getn_u16(&buf[12..14]), 41 | getn_u16(&buf[14..16]), 42 | )) 43 | } 44 | /// Stores ipv6 address into the buffer. 45 | pub fn encode_addrv6_to(addr: &std::net::Ipv6Addr, buf: &mut [u8]) -> Result { 46 | if buf.len() < 16 { 47 | return Err(BgpError::static_str("Invalid addrv6 length")); 48 | } 49 | buf[0..16].clone_from_slice(&addr.octets()); 50 | Ok(16) 51 | } 52 | /// Gets ipv4/ipv6 address from the buffer. Address type determined by buffer length. 53 | pub fn decode_addr_from(buf: &[u8]) -> Result { 54 | match buf.len() { 55 | 16 => Ok(std::net::IpAddr::V6(decode_addrv6_from(buf)?)), 56 | 4 => Ok(std::net::IpAddr::V4(decode_addrv4_from(buf)?)), 57 | _ => Err(BgpError::static_str("Invalid addr length")), 58 | } 59 | } 60 | /// Stores ipv4/ipv6 address into the buffer. 61 | pub fn encode_addr_to(addr: &std::net::IpAddr, buf: &mut [u8]) -> Result { 62 | match addr { 63 | std::net::IpAddr::V4(a) => encode_addrv4_to(a, buf), 64 | std::net::IpAddr::V6(a) => encode_addrv6_to(a, buf), 65 | } 66 | } 67 | pub fn ntoh16(a: u16) -> u16 { 68 | (a >> 8) | ((a & 0xff) << 8) 69 | } 70 | pub fn setn_u16(s: u16, a: &mut [u8]) { 71 | a[0] = (s >> 8) as u8; 72 | a[1] = (s & 0xff) as u8; 73 | } 74 | pub fn getn_u16(a: &[u8]) -> u16 { 75 | (a[0] as u16) << 8 | (a[1] as u16) 76 | } 77 | pub fn getn_u32(a: &[u8]) -> u32 { 78 | (a[0] as u32) << 24 | (a[1] as u32) << 16 | (a[2] as u32) << 8 | (a[3] as u32) 79 | } 80 | pub fn setn_u32(s: u32, a: &mut [u8]) { 81 | a[0] = (s >> 24) as u8; 82 | a[1] = ((s >> 16) & 0xff) as u8; 83 | a[2] = ((s >> 8) & 0xff) as u8; 84 | a[3] = (s & 0xff) as u8; 85 | } 86 | pub fn getn_u64(a: &[u8]) -> u64 { 87 | ((getn_u32(a) as u64) << 32) | (getn_u32(&a[4..8]) as u64) 88 | } 89 | pub fn setn_u64(s: u64, a: &mut [u8]) { 90 | a[0] = (s >> 56) as u8; 91 | a[1] = ((s >> 48) & 0xff) as u8; 92 | a[2] = ((s >> 40) & 0xff) as u8; 93 | a[3] = ((s >> 32) & 0xff) as u8; 94 | a[4] = ((s >> 24) & 0xff) as u8; 95 | a[5] = ((s >> 16) & 0xff) as u8; 96 | a[6] = ((s >> 8) & 0xff) as u8; 97 | a[7] = (s & 0xff) as u8; 98 | } 99 | pub fn getn_u128(a: &[u8]) -> u128 { 100 | ((getn_u64(a) as u128) << 64) | (getn_u64(&a[8..16]) as u128) 101 | } 102 | pub(crate) fn is_addpath_nlri(b: &[u8]) -> bool { 103 | if b.len() < 5 { 104 | false 105 | } else { 106 | b[0] == 0 && b[1] == 0 107 | } 108 | } 109 | /// Returns BgpError::InsufficientBufferSize if slicing is out of bounds 110 | pub fn slice(buf: &[T], start: usize, end: usize) -> Result<&[T], BgpError> { 111 | if start <= end && end <= buf.len() { 112 | Ok(&buf[start..end]) 113 | } else { 114 | Err(BgpError::InsufficientBufferSize) 115 | } 116 | } 117 | /// Returns BgpError::InsufficientBufferSize if slicing is out of bounds 118 | pub fn slice_mut(buf: &mut [T], start: usize, end: usize) -> Result<&mut [T], BgpError> { 119 | if start <= end && end <= buf.len() { 120 | Ok(&mut buf[start..end]) 121 | } else { 122 | Err(BgpError::InsufficientBufferSize) 123 | } 124 | } 125 | --------------------------------------------------------------------------------