Misc cleanups
Some checks are pending
Rust / build (push) Waiting to run

This commit is contained in:
Rayhaan Jaufeerally
2024-08-18 13:59:28 +00:00
parent 82d052ca33
commit 0e45b96440
6 changed files with 132 additions and 164 deletions

View File

@ -28,7 +28,6 @@ use serde::{Deserialize, Serialize};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt; use std::fmt;
use std::io::ErrorKind;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr; use std::str::FromStr;
@ -283,7 +282,7 @@ mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
use super::NLRI; use super::NLRI;
use crate::constants::AddressFamilyIdentifier::{Ipv4, Ipv6}; use crate::constants::AddressFamilyIdentifier::{self, Ipv4, Ipv6};
use crate::traits::ParserContext; use crate::traits::ParserContext;
use crate::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::traits::WritablePacket; use crate::traits::WritablePacket;
@ -373,17 +372,4 @@ mod tests {
assert_eq!(reparsed, parsed_nlri); assert_eq!(reparsed, parsed_nlri);
} }
} }
// #[test]
// fn test_to_string_invalids() {
// let invalid_v4 = NLRI {
// afi: AddressFamilyIdentifier::Ipv4,
// prefix: vec![1, 2, 3, 4, 5],
// prefixlen: 16,
// };
// assert_eq!(
// "a formatting trait implementation returned an error: Error",
// format!("{}", invalid_v4)
// );
// }
} }

View File

@ -6,7 +6,6 @@ use netlink_packet_route::route::RouteAddress;
use netlink_packet_route::route::RouteAttribute; use netlink_packet_route::route::RouteAttribute;
use netlink_packet_route::route::RouteHeader; use netlink_packet_route::route::RouteHeader;
use netlink_packet_route::route::RouteMessage; use netlink_packet_route::route::RouteMessage;
use netlink_packet_route::route::RouteProtocol;
use netlink_packet_route::route::RouteType; use netlink_packet_route::route::RouteType;
use netlink_packet_route::AddressFamily as NetlinkAddressFamily; use netlink_packet_route::AddressFamily as NetlinkAddressFamily;
use rtnetlink::IpVersion; use rtnetlink::IpVersion;

View File

@ -185,33 +185,6 @@ async fn start_http_server(
Ok(warp::http::Response::builder().body(result).into_response()) Ok(warp::http::Response::builder().body(result).into_response())
} }
/*
async fn modify_community_fn(
add: bool,
peers: HashMap<String, UnboundedSender<PeerCommands>>,
name: String,
ld1: u32,
ld2: u32,
) -> Result<impl warp::Reply, warp::Rejection> {
if let Some(chan) = peers.get(&name) {
if let Err(e) = func(chan.clone(), ld1, ld2).await {
warn!("Failed to add large community: {:?}", e);
return Err(warp::reject());
}
} else {
return Err(warp::reject());
}
Ok(warp::reply::with_status("Ok", warp::http::StatusCode::OK))
}
let add_community_filter = warp::post()
.map(move || true)
.and(warp::path::param())
.and(warp::path!(u32 / u32))
.and_then(modify_community_fn);
*/
// Start the web server that has access to the rib managers so that it can expose the state. // Start the web server that has access to the rib managers so that it can expose the state.
let v4_mgr_filter = warp::any().map(move || manager4.clone()); let v4_mgr_filter = warp::any().map(move || manager4.clone());

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::config::PrefixAnnouncement;
use crate::config::{PeerConfig, ServerConfig}; use crate::config::{PeerConfig, ServerConfig};
use crate::data_structures::RouteWithdraw; use crate::data_structures::RouteWithdraw;
use crate::data_structures::{RouteInfo, RouteUpdate}; use crate::data_structures::{RouteInfo, RouteUpdate};
@ -45,6 +44,7 @@ use bgp_packet::path_attributes::{
}; };
use bgp_packet::traits::ParserContext; use bgp_packet::traits::ParserContext;
use bytes::BytesMut; use bytes::BytesMut;
use chrono::TimeZone;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use eyre::{bail, eyre}; use eyre::{bail, eyre};
use ip_network_table_deps_treebitmap::address::Address; use ip_network_table_deps_treebitmap::address::Address;
@ -53,8 +53,8 @@ use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use std::net::IpAddr; use std::net::IpAddr;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::sync::RwLock;
use std::time::Duration; use std::time::Duration;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
@ -165,8 +165,8 @@ async fn run_timer(
async fn check_hold_timer( async fn check_hold_timer(
cancel_token: CancellationToken, cancel_token: CancellationToken,
iface: PeerInterface, iface: PeerInterface,
last_msg_time: Arc<RwLock<DateTime<Utc>>>, last_msg_time: Arc<AtomicI64>,
hold_time: std::time::Duration, hold_time: chrono::Duration,
) { ) {
loop { loop {
tokio::select! { tokio::select! {
@ -175,9 +175,17 @@ async fn check_hold_timer(
return; return;
} }
_ = tokio::time::sleep(std::time::Duration::from_secs(1)) => { _ = tokio::time::sleep(std::time::Duration::from_secs(1)) => {
let last = last_msg_time.read().unwrap(); let now = Utc::now();
let elapsed_time = Utc::now() - *last; let last_msg = match Utc.timestamp_millis_opt(last_msg_time.load(Ordering::Relaxed)) {
if elapsed_time.num_seconds() as u64 > hold_time.as_secs() { chrono::offset::LocalResult::Single(t) => t,
chrono::offset::LocalResult::Ambiguous(earliest, _) => earliest,
chrono::offset::LocalResult::None => {
warn!("Failed to parse last msg time");
continue;
},
};
if (now - last_msg) > hold_time {
match iface.send(PeerCommands::TimerEvent(PeerTimerEvent::HoldTimerExpire())) { match iface.send(PeerCommands::TimerEvent(PeerTimerEvent::HoldTimerExpire())) {
Ok(()) => {}, Ok(()) => {},
Err(e) => { Err(e) => {
@ -187,6 +195,7 @@ async fn check_hold_timer(
// Exit the hold timer task since it's expired already and is not needed anymore. // Exit the hold timer task since it's expired already and is not needed anymore.
return; return;
} }
} }
} }
@ -336,7 +345,7 @@ pub struct PeerStateMachine<A: Address> {
// Keep track of the time of the last message to efficiently implement // Keep track of the time of the last message to efficiently implement
// the hold timer. // the hold timer.
last_msg_time: Arc<RwLock<DateTime<Utc>>>, last_msg_time: Arc<AtomicI64>,
// Timers and cancellation token to spawned tasks // Timers and cancellation token to spawned tasks
connect_timer: Option<(JoinHandle<()>, CancellationToken)>, connect_timer: Option<(JoinHandle<()>, CancellationToken)>,
@ -380,7 +389,7 @@ where
iface_tx, iface_tx,
route_manager, route_manager,
established_time: None, established_time: None,
last_msg_time: Arc::new(RwLock::new(DateTime::from_timestamp(0, 0).unwrap())), last_msg_time: Arc::new(AtomicI64::default()),
connect_timer: None, connect_timer: None,
hold_timer: None, hold_timer: None,
keepalive_timer: None, keepalive_timer: None,
@ -519,13 +528,9 @@ where
} }
PeerCommands::MessageFromPeer(msg) => match self.handle_msg(msg).await { PeerCommands::MessageFromPeer(msg) => match self.handle_msg(msg).await {
Ok(_) => { Ok(_) => self
let mut last_time = self
.last_msg_time .last_msg_time
.write() .store(Utc::now().timestamp_millis(), Ordering::Relaxed),
.map_err(|e| eyre!(e.to_string()))?;
*last_time = Utc::now();
}
Err(e) => { Err(e) => {
bail!(e); bail!(e);
} }
@ -580,7 +585,7 @@ where
}, },
state: format!("{:?}", self.state), state: format!("{:?}", self.state),
session_established_time: self.established_time.map(|t| t.timestamp() as u64), session_established_time: self.established_time.map(|t| t.timestamp() as u64),
last_messaage_time: Some(self.last_msg_time.read().unwrap().timestamp() as u64), last_messaage_time: Some(self.last_msg_time.load(Ordering::Relaxed) as u64),
route_updates_in: Some(0), /* todo */ route_updates_in: Some(0), /* todo */
route_updates_out: Some(0), /* todo */ route_updates_out: Some(0), /* todo */
}; };
@ -1066,9 +1071,10 @@ where
if hold_time > 0 { if hold_time > 0 {
// Set keepalive timer. // Set keepalive timer.
let keepalive_duration = hold_time / 3; let keepalive_duration = hold_time / 3;
info!( trace!(
"Using keepalive duration of {} for peer {}", "Using keepalive duration of {} for peer {}",
keepalive_duration, self.config.name keepalive_duration,
self.config.name
); );
{ {
let token = CancellationToken::new(); let token = CancellationToken::new();
@ -1098,7 +1104,7 @@ where
token_copy, token_copy,
chan, chan,
last_msg_time, last_msg_time,
std::time::Duration::from_secs(hold_time.into()), chrono::Duration::seconds(hold_time.into()),
) )
.await .await
}); });
@ -1107,11 +1113,7 @@ where
} }
}; };
// TODO: Should not have to clone here? self.announce_static().await?;
let announcements: Vec<PrefixAnnouncement> = self.config.announcements.clone();
for announcement in announcements {
self.announce_static(&announcement).await?;
}
Ok(()) Ok(())
} }
@ -1135,7 +1137,9 @@ where
Ok(()) Ok(())
} }
async fn announce_static(&mut self, announcement: &PrefixAnnouncement) -> eyre::Result<()> { /// Generates and sends announcements for all statically defined routes.
async fn announce_static(&mut self) -> eyre::Result<()> {
for announcement in &self.config.announcements {
let mut bgp_update_msg = UpdateMessage { let mut bgp_update_msg = UpdateMessage {
withdrawn_nlri: vec![], withdrawn_nlri: vec![],
announced_nlri: vec![], announced_nlri: vec![],
@ -1154,13 +1158,9 @@ where
match self.config.afi { match self.config.afi {
AddressFamilyIdentifier::Ipv4 => { AddressFamilyIdentifier::Ipv4 => {
match announcement.nexthop { match announcement.nexthop {
IpAddr::V4(nh) => { IpAddr::V4(nh) => bgp_update_msg.path_attributes.push(
bgp_update_msg PathAttribute::NextHopPathAttribute(NextHopPathAttribute(nh)),
.path_attributes ),
.push(PathAttribute::NextHopPathAttribute(NextHopPathAttribute(
nh,
)))
}
_ => bail!("Found non IPv4 nexthop in announcement"), _ => bail!("Found non IPv4 nexthop in announcement"),
} }
@ -1233,6 +1233,7 @@ where
.await .await
.map_err(|e| eyre!("Failed to write msg to peer: {}", e))?; .map_err(|e| eyre!("Failed to write msg to peer: {}", e))?;
} }
}
Ok(()) Ok(())
} }

View File

@ -213,9 +213,8 @@ where
for pathset in self.rib.iter() { for pathset in self.rib.iter() {
snapshot.routes.push(pathset.2.lock().unwrap().clone()); snapshot.routes.push(pathset.2.lock().unwrap().clone());
} }
// TODO: handle an error here.
if let Err(e) = sender.send(snapshot) { if let Err(e) = sender.send(snapshot) {
warn!("Failed to send snapshot of RIB: {:?}", e); trace!("Failed to send snapshot of RIB: {:?}", e);
} }
info!("Done RIB dump"); info!("Done RIB dump");
} }

View File

@ -110,21 +110,31 @@ impl RouteServer {
impl BgpServerAdminService for RouteServer { impl BgpServerAdminService for RouteServer {
async fn peer_status( async fn peer_status(
&self, &self,
request: tonic::Request<PeerStatusRequest>, _request: tonic::Request<PeerStatusRequest>,
) -> Result<Response<PeerStatusResponse>, Status> { ) -> Result<Response<PeerStatusResponse>, Status> {
let mut result = PeerStatusResponse::default(); let mut result = PeerStatusResponse::default();
// Store the pending futures in a JoinSet to parallelize fetching.
let mut join_set = tokio::task::JoinSet::new();
for peer in &self.peer_state_machines { for peer in &self.peer_state_machines {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
if let Err(e) = peer.1.send(PeerCommands::GetStatus(tx)) { if let Err(_e) = peer.1.send(PeerCommands::GetStatus(tx)) {
warn!( warn!(
peer = peer.0, peer = peer.0,
"Peer channel dead when trying to send state request" "Failed to send GetStatus request to PeerStateMachine"
); );
continue; continue;
} }
let resp = rx.await.map_err(|e| Status::internal(format!("{}", e)))?; join_set.spawn(rx);
result.peer_status.push(resp); }
while let Some(next) = join_set.join_next().await {
match next {
Ok(Ok(peer_status)) => result.peer_status.push(peer_status),
Ok(Err(e)) => return Err(Status::internal(format!("{}", e))),
Err(e) => return Err(Status::internal(format!("{}", e))),
}
} }
Ok(Response::new(result)) Ok(Response::new(result))