mirror of
https://github.com/mii443/miibgpd.git
synced 2025-12-03 02:58:23 +00:00
implement complete UpdateMessage
This commit is contained in:
@@ -27,3 +27,10 @@ pub struct ConvertbgpMessageToBytesError {
|
|||||||
#[from]
|
#[from]
|
||||||
source: anyhow::Error,
|
source: anyhow::Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error(transparent)]
|
||||||
|
pub struct ConstructIpv4NetworkError {
|
||||||
|
#[from]
|
||||||
|
source: anyhow::Error,
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::bgp_type::AutonomousSystemNumber;
|
|||||||
use crate::error::ConvertBytesToBgpMessageError;
|
use crate::error::ConvertBytesToBgpMessageError;
|
||||||
use crate::path_attribute::{AsPath, Origin, PathAttribute};
|
use crate::path_attribute::{AsPath, Origin, PathAttribute};
|
||||||
use crate::routing::Ipv4Network;
|
use crate::routing::Ipv4Network;
|
||||||
|
use anyhow::Context;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
|
|
||||||
use super::header::{Header, MessageType};
|
use super::header::{Header, MessageType};
|
||||||
@@ -90,7 +91,42 @@ impl TryFrom<BytesMut> for UpdateMessage {
|
|||||||
type Error = ConvertBytesToBgpMessageError;
|
type Error = ConvertBytesToBgpMessageError;
|
||||||
|
|
||||||
fn try_from(bytes: BytesMut) -> Result<Self, Self::Error> {
|
fn try_from(bytes: BytesMut) -> Result<Self, Self::Error> {
|
||||||
todo!();
|
let header = Header::try_from(BytesMut::from(&bytes[0..19]))?;
|
||||||
|
|
||||||
|
let withdrawn_routes_length: u16 = u16::from_be_bytes(bytes[19..21].try_into().context(
|
||||||
|
format!("cannot convert to withdrawn_routes_length: {:?}", &bytes),
|
||||||
|
)?);
|
||||||
|
let withdrawn_routes_end_index = 21 + withdrawn_routes_length as usize;
|
||||||
|
let withdrawn_routes_bytes = &bytes[21..withdrawn_routes_end_index];
|
||||||
|
let withdrawn_routes = Ipv4Network::from_u8_slice(withdrawn_routes_bytes)?;
|
||||||
|
|
||||||
|
let path_attributes_start_index = withdrawn_routes_end_index + 2;
|
||||||
|
let total_path_attribute_length = u16::from_be_bytes(
|
||||||
|
bytes[withdrawn_routes_end_index..path_attributes_start_index]
|
||||||
|
.try_into()
|
||||||
|
.context(format!(
|
||||||
|
"cannot convert to total_path_attribute_length: {:?}",
|
||||||
|
&bytes
|
||||||
|
))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let path_attributes_bytes = &bytes[path_attributes_start_index
|
||||||
|
..path_attributes_start_index + total_path_attribute_length as usize];
|
||||||
|
let path_attributes = Arc::new(PathAttribute::from_u8_slice(path_attributes_bytes)?);
|
||||||
|
let network_layer_reachability_information_start_index =
|
||||||
|
path_attributes_start_index + total_path_attribute_length as usize;
|
||||||
|
let network_layer_reachability_information = Ipv4Network::from_u8_slice(
|
||||||
|
&bytes[network_layer_reachability_information_start_index..],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
header,
|
||||||
|
withdrawn_routes,
|
||||||
|
withdrawn_routes_length,
|
||||||
|
path_attributes,
|
||||||
|
path_attributes_length: total_path_attribute_length,
|
||||||
|
network_layer_reachability_information,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +150,7 @@ mod tests {
|
|||||||
|
|
||||||
let update_message = UpdateMessage::new(
|
let update_message = UpdateMessage::new(
|
||||||
update_message_path_attributes,
|
update_message_path_attributes,
|
||||||
vec!["10.100.220.0.24".parse().unwrap()],
|
vec!["10.100.220.0/24".parse().unwrap()],
|
||||||
vec![],
|
vec![],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
use anyhow::Context;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
|
|
||||||
use crate::bgp_type::AutonomousSystemNumber;
|
use crate::bgp_type::AutonomousSystemNumber;
|
||||||
|
use crate::error::ConvertBytesToBgpMessageError;
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
@@ -61,6 +63,50 @@ impl From<&AsPath> for BytesMut {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for Origin {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(Origin::Igp),
|
||||||
|
1 => Ok(Origin::Egp),
|
||||||
|
2 => Ok(Origin::Incomplete),
|
||||||
|
_ => Err(anyhow::anyhow!("cannot convert to Origin: {:?}", value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&[u8]> for AsPath {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||||
|
match value[0] {
|
||||||
|
1 => {
|
||||||
|
let mut ases = BTreeSet::new();
|
||||||
|
let mut i = 2;
|
||||||
|
while i < value.len() {
|
||||||
|
ases.insert(u16::from_be_bytes(value[i..i + 2].try_into()?).into());
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
Ok(AsPath::AsSet(ases))
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let mut ases = Vec::new();
|
||||||
|
let mut i = 2;
|
||||||
|
while i < value.len() {
|
||||||
|
ases.push(u16::from_be_bytes(value[i..i + 2].try_into()?).into());
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
Ok(AsPath::AsSequence(ases))
|
||||||
|
}
|
||||||
|
_ => Err(anyhow::anyhow!(format!(
|
||||||
|
"cannot convert to AsPath: {:?}",
|
||||||
|
value
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PathAttribute {
|
impl PathAttribute {
|
||||||
pub fn bytes_len(&self) -> usize {
|
pub fn bytes_len(&self) -> usize {
|
||||||
let path_attribute_value_length = match self {
|
let path_attribute_value_length = match self {
|
||||||
@@ -78,6 +124,51 @@ impl PathAttribute {
|
|||||||
length + 1
|
length + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_u8_slice(
|
||||||
|
bytes: &[u8],
|
||||||
|
) -> Result<Vec<PathAttribute>, ConvertBytesToBgpMessageError> {
|
||||||
|
let mut path_attributes = vec![];
|
||||||
|
let mut i = 0;
|
||||||
|
while bytes.len() > i {
|
||||||
|
let attribute_flag = bytes[i];
|
||||||
|
let attribute_length_octets = ((attribute_flag & 0b0001_0000) >> 4) + 1;
|
||||||
|
let attribute_type_code = bytes[i + 1];
|
||||||
|
let attribute_length = if attribute_length_octets == 1 {
|
||||||
|
bytes[i + 2] as usize
|
||||||
|
} else {
|
||||||
|
u16::from_be_bytes(
|
||||||
|
bytes[i + 2..i + 4]
|
||||||
|
.try_into()
|
||||||
|
.context("cannot convert to attribute_length")?,
|
||||||
|
) as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let attribute_start_index = i + 1 + attribute_length_octets as usize + 1;
|
||||||
|
let attribute_end_index = attribute_start_index + attribute_length;
|
||||||
|
let path_attribute = match attribute_type_code {
|
||||||
|
1 => PathAttribute::Origin(Origin::try_from(bytes[attribute_start_index])?),
|
||||||
|
2 => PathAttribute::AsPath(AsPath::try_from(
|
||||||
|
&bytes[attribute_start_index..attribute_end_index],
|
||||||
|
)?),
|
||||||
|
3 => {
|
||||||
|
let addr = Ipv4Addr::new(
|
||||||
|
bytes[attribute_start_index],
|
||||||
|
bytes[attribute_start_index + 1],
|
||||||
|
bytes[attribute_start_index + 2],
|
||||||
|
bytes[attribute_start_index + 3],
|
||||||
|
);
|
||||||
|
|
||||||
|
PathAttribute::NextHop(addr)
|
||||||
|
}
|
||||||
|
_ => PathAttribute::DontKnow(bytes[i..attribute_end_index].to_owned()),
|
||||||
|
};
|
||||||
|
path_attributes.push(path_attribute);
|
||||||
|
i = attribute_end_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(path_attributes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&PathAttribute> for BytesMut {
|
impl From<&PathAttribute> for BytesMut {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
net::IpAddr,
|
net::{IpAddr, Ipv4Addr},
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
@@ -10,7 +10,10 @@ use futures::TryStreamExt;
|
|||||||
use rtnetlink::{new_connection, IpVersion};
|
use rtnetlink::{new_connection, IpVersion};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{config::Config, error::ConfigParseError};
|
use crate::{
|
||||||
|
config::Config,
|
||||||
|
error::{ConfigParseError, ConstructIpv4NetworkError, ConvertBytesToBgpMessageError},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
struct LocRib;
|
struct LocRib;
|
||||||
@@ -74,6 +77,70 @@ impl From<&Ipv4Network> for BytesMut {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ipv4Network {
|
impl Ipv4Network {
|
||||||
|
pub fn new(addr: Ipv4Addr, prefix: u8) -> Result<Self, ConstructIpv4NetworkError> {
|
||||||
|
let network = ipnetwork::Ipv4Network::new(addr, prefix).context(format!(
|
||||||
|
"cannot create Ipv4Network: {:?}, {:?}",
|
||||||
|
addr, prefix
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(Self(network))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u8_slice(bytes: &[u8]) -> Result<Vec<Self>, ConvertBytesToBgpMessageError> {
|
||||||
|
let mut networks = vec![];
|
||||||
|
let mut i = 0;
|
||||||
|
while bytes.len() > i {
|
||||||
|
let prefix = bytes[i];
|
||||||
|
i += 1;
|
||||||
|
match prefix {
|
||||||
|
0 => {
|
||||||
|
networks.push(Ipv4Network::new(Ipv4Addr::new(0, 0, 0, 0), prefix).context("")?);
|
||||||
|
}
|
||||||
|
1..=8 => {
|
||||||
|
networks.push(
|
||||||
|
Ipv4Network::new(Ipv4Addr::new(bytes[i], 0, 0, 0), prefix).context("")?,
|
||||||
|
);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
9..=16 => {
|
||||||
|
networks.push(
|
||||||
|
Ipv4Network::new(Ipv4Addr::new(bytes[i], bytes[i + 1], 0, 0), prefix)
|
||||||
|
.context("")?,
|
||||||
|
);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
17..=24 => {
|
||||||
|
networks.push(
|
||||||
|
Ipv4Network::new(
|
||||||
|
Ipv4Addr::new(bytes[i], bytes[i + 1], bytes[i + 2], 0),
|
||||||
|
prefix,
|
||||||
|
)
|
||||||
|
.context("")?,
|
||||||
|
);
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
25..=32 => {
|
||||||
|
networks.push(
|
||||||
|
Ipv4Network::new(
|
||||||
|
Ipv4Addr::new(bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3]),
|
||||||
|
prefix,
|
||||||
|
)
|
||||||
|
.context("")?,
|
||||||
|
);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ConvertBytesToBgpMessageError::from(anyhow::anyhow!(
|
||||||
|
"Invalid prefix length: {:?}",
|
||||||
|
prefix
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(networks)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bytes_len(&self) -> usize {
|
pub fn bytes_len(&self) -> usize {
|
||||||
match self.prefix() {
|
match self.prefix() {
|
||||||
0 => 1,
|
0 => 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user