This commit is contained in:
@ -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)
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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());
|
||||||
|
|
||||||
|
|||||||
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
Reference in New Issue
Block a user