scion_stack/path/strategy/
ranking.rs

1// Copyright 2025 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Path ranking allows expressing preferences between paths.
16//!
17//! For example, preferring shorter paths, paths that were manually registered, or paths
18//! that go through certain ASes.
19
20use std::cmp::Ordering;
21
22use crate::path::types::PathManagerPath;
23
24/// Scion path ranking allows expressing preferences between paths.
25pub trait PathRanking: 'static + Send + Sync {
26    /// Ranks the order of two paths based on preference.
27    ///
28    /// # Return
29    /// Returns the **preference ordering** between two paths.
30    ///
31    /// - `Ordering::Less` if `this` is preferred over `other`
32    /// - `Ordering::Greater` if `other` is preferred over `this`
33    /// - `Ordering::Equal` if both paths are equally preferred
34    fn rank_order(&self, this: &PathManagerPath, other: &PathManagerPath) -> Ordering;
35}
36
37/// Selects the shortest path based on the number of hops.
38pub struct Shortest;
39
40impl PathRanking for Shortest {
41    fn rank_order(&self, this: &PathManagerPath, other: &PathManagerPath) -> Ordering {
42        // Prefer paths that were manually registered.
43        match (this.is_from_registration(), other.is_from_registration()) {
44            (true, false) => Ordering::Less,
45            (false, true) => Ordering::Greater,
46            _ => {
47                // Prefer shorter paths.
48                this.path
49                    .interface_count()
50                    .cmp(&other.path.interface_count())
51            }
52        }
53    }
54}