This commit is contained in:
John Smith 2022-11-13 12:48:44 -05:00
parent fd26acec16
commit 4a9d516f32
2 changed files with 56 additions and 16 deletions

View File

@ -388,12 +388,21 @@ impl RouteSpecStore {
sequencing: Sequencing, sequencing: Sequencing,
hop_count: usize, hop_count: usize,
directions: DirectionSet, directions: DirectionSet,
avoid_node_id: Option<DHTKey>,
) -> EyreResult<Option<DHTKey>> { ) -> EyreResult<Option<DHTKey>> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
let routing_table = self.unlocked_inner.routing_table.clone(); let routing_table = self.unlocked_inner.routing_table.clone();
let rti = &mut *routing_table.inner.write(); let rti = &mut *routing_table.inner.write();
self.allocate_route_inner(inner, rti, stability, sequencing, hop_count, directions) self.allocate_route_inner(
inner,
rti,
stability,
sequencing,
hop_count,
directions,
avoid_node_id,
)
} }
fn allocate_route_inner( fn allocate_route_inner(
@ -404,6 +413,7 @@ impl RouteSpecStore {
sequencing: Sequencing, sequencing: Sequencing,
hop_count: usize, hop_count: usize,
directions: DirectionSet, directions: DirectionSet,
avoid_node_id: Option<DHTKey>,
) -> EyreResult<Option<DHTKey>> { ) -> EyreResult<Option<DHTKey>> {
use core::cmp::Ordering; use core::cmp::Ordering;
@ -418,7 +428,7 @@ impl RouteSpecStore {
// Get list of all nodes, and sort them for selection // Get list of all nodes, and sort them for selection
let cur_ts = intf::get_timestamp(); let cur_ts = intf::get_timestamp();
let filter = Box::new( let filter = Box::new(
move |rti: &RoutingTableInner, _k: DHTKey, v: Option<Arc<BucketEntry>>| -> bool { move |rti: &RoutingTableInner, k: DHTKey, v: Option<Arc<BucketEntry>>| -> bool {
// Exclude our own node from routes // Exclude our own node from routes
if v.is_none() { if v.is_none() {
return false; return false;
@ -433,6 +443,13 @@ impl RouteSpecStore {
return false; return false;
} }
// Exclude node we have specifically chosen to avoid
if let Some(ani) = avoid_node_id {
if k == ani {
return false;
}
}
// Exclude nodes with no publicinternet nodeinfo, or incompatible nodeinfo or node status won't route // Exclude nodes with no publicinternet nodeinfo, or incompatible nodeinfo or node status won't route
v.with(rti, move |_rti, e| { v.with(rti, move |_rti, e| {
let node_info_ok = let node_info_ok =
@ -748,6 +765,7 @@ impl RouteSpecStore {
stability: Stability, stability: Stability,
sequencing: Sequencing, sequencing: Sequencing,
directions: DirectionSet, directions: DirectionSet,
avoid_node_id: Option<DHTKey>,
) -> Option<DHTKey> { ) -> Option<DHTKey> {
let inner = self.inner.lock(); let inner = self.inner.lock();
@ -759,7 +777,15 @@ impl RouteSpecStore {
&& detail.1.directions.is_subset(directions) && detail.1.directions.is_subset(directions)
&& !detail.1.published && !detail.1.published
{ {
return Some(*detail.0); let mut avoid = false;
if let Some(ani) = &avoid_node_id {
if detail.1.hops.contains(ani) {
avoid = true;
}
}
if !avoid {
return Some(*detail.0);
}
} }
} }
None None
@ -800,16 +826,15 @@ impl RouteSpecStore {
if pr_hopcount > max_route_hop_count { if pr_hopcount > max_route_hop_count {
bail!("private route hop count too long"); bail!("private route hop count too long");
} }
let Some(pr_first_hop) = &private_route.first_hop else {
bail!("compiled private route should have first_hop");
};
// See if we are using a safety route, if not, short circuit this operation // See if we are using a safety route, if not, short circuit this operation
let safety_spec = match safety_selection { let safety_spec = match safety_selection {
SafetySelection::Unsafe(sequencing) => { SafetySelection::Unsafe(sequencing) => {
// Safety route stub with the node's public key as the safety route key since it's the 0th hop // Safety route stub with the node's public key as the safety route key since it's the 0th hop
if private_route.first_hop.is_none() { let opt_first_hop = match &pr_first_hop.node {
bail!("can't compile zero length route");
}
let first_hop = private_route.first_hop.as_ref().unwrap();
let opt_first_hop = match &first_hop.node {
RouteNode::NodeId(id) => rti.lookup_node_ref(routing_table.clone(), id.key), RouteNode::NodeId(id) => rti.lookup_node_ref(routing_table.clone(), id.key),
RouteNode::PeerInfo(pi) => rti.register_node_with_signed_node_info( RouteNode::PeerInfo(pi) => rti.register_node_with_signed_node_info(
routing_table.clone(), routing_table.clone(),
@ -851,6 +876,13 @@ impl RouteSpecStore {
// Safety route exists // Safety route exists
safety_rsd safety_rsd
} else { } else {
// Avoid having the first node in the private route in our chosen safety route
// We would avoid all of them, but by design only the first node is knowable
let avoid_node_id = match &pr_first_hop.node {
RouteNode::NodeId(n) => n.key,
RouteNode::PeerInfo(p) => p.node_id.key,
};
// Select a safety route from the pool or make one if we don't have one that matches // Select a safety route from the pool or make one if we don't have one that matches
if let Some(sr_pubkey) = self.first_unpublished_route( if let Some(sr_pubkey) = self.first_unpublished_route(
safety_spec.hop_count, safety_spec.hop_count,
@ -858,6 +890,7 @@ impl RouteSpecStore {
safety_spec.stability, safety_spec.stability,
safety_spec.sequencing, safety_spec.sequencing,
Direction::Outbound.into(), Direction::Outbound.into(),
Some(avoid_node_id),
) { ) {
// Found a route to use // Found a route to use
(Self::detail_mut(inner, &sr_pubkey).unwrap(), sr_pubkey) (Self::detail_mut(inner, &sr_pubkey).unwrap(), sr_pubkey)
@ -871,6 +904,7 @@ impl RouteSpecStore {
safety_spec.sequencing, safety_spec.sequencing,
safety_spec.hop_count, safety_spec.hop_count,
Direction::Outbound.into(), Direction::Outbound.into(),
Some(avoid_node_id),
) )
.map_err(RPCError::internal)? .map_err(RPCError::internal)?
{ {

View File

@ -566,7 +566,7 @@ impl VeilidAPI {
} }
async fn debug_route_allocate(&self, args: Vec<String>) -> Result<String, VeilidAPIError> { async fn debug_route_allocate(&self, args: Vec<String>) -> Result<String, VeilidAPIError> {
// [ord|*ord] [rel] [<count>] [in|out] // [ord|*ord] [rel] [<count>] [in|out] [avoid_node_id]
let netman = self.network_manager()?; let netman = self.network_manager()?;
let routing_table = netman.routing_table(); let routing_table = netman.routing_table();
@ -582,6 +582,7 @@ impl VeilidAPI {
let mut stability = Stability::LowLatency; let mut stability = Stability::LowLatency;
let mut hop_count = default_route_hop_count; let mut hop_count = default_route_hop_count;
let mut directions = DirectionSet::all(); let mut directions = DirectionSet::all();
let mut avoid_node_id = None;
while ai < args.len() { while ai < args.len() {
if let Ok(seq) = if let Ok(seq) =
@ -600,6 +601,10 @@ impl VeilidAPI {
get_debug_argument_at(&args, ai, "debug_route", "direction_set", get_direction_set) get_debug_argument_at(&args, ai, "debug_route", "direction_set", get_direction_set)
{ {
directions = ds; directions = ds;
} else if let Ok(ani) =
get_debug_argument_at(&args, ai, "debug_route", "avoid_node_id", get_dht_key)
{
avoid_node_id = Some(ani);
} else { } else {
return Ok(format!("Invalid argument specified: {}", args[ai])); return Ok(format!("Invalid argument specified: {}", args[ai]));
} }
@ -607,13 +612,14 @@ impl VeilidAPI {
} }
// Allocate route // Allocate route
let out = match rss.allocate_route(stability, sequencing, hop_count, directions) { let out =
Ok(Some(v)) => format!("{}", v.encode()), match rss.allocate_route(stability, sequencing, hop_count, directions, avoid_node_id) {
Ok(None) => format!("<unavailable>"), Ok(Some(v)) => format!("{}", v.encode()),
Err(e) => { Ok(None) => format!("<unavailable>"),
format!("Route allocation failed: {}", e) Err(e) => {
} format!("Route allocation failed: {}", e)
}; }
};
Ok(out) Ok(out)
} }