Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add datagram trait and path-aware datagram #106

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions crates/scion-proto/src/address/scion_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ impl ScionAddr {
}
}

impl AsRef<IsdAsn> for ScionAddr {
fn as_ref(&self) -> &IsdAsn {
match self {
ScionAddr::V4(addr) => addr.as_ref(),
ScionAddr::V6(addr) => addr.as_ref(),
ScionAddr::Svc(addr) => addr.as_ref(),
}
}
}

macro_rules! impl_from {
($base:ty, $variant:expr) => {
impl From<$base> for ScionAddr {
Expand Down Expand Up @@ -155,6 +165,12 @@ macro_rules! scion_address {
}
}

impl AsRef<IsdAsn> for $name {
fn as_ref(&self) -> &IsdAsn {
&self.isd_asn
}
}

impl core::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{},{}", self.isd_asn(), self.host())
Expand Down
16 changes: 16 additions & 0 deletions crates/scion-proto/src/address/socket_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ impl SocketAddr {
}
}

impl AsRef<IsdAsn> for SocketAddr {
fn as_ref(&self) -> &IsdAsn {
match self {
SocketAddr::V4(addr) => addr.as_ref(),
SocketAddr::V6(addr) => addr.as_ref(),
SocketAddr::Svc(addr) => addr.as_ref(),
}
}
}

impl From<SocketAddrV4> for SocketAddr {
/// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
#[inline]
Expand Down Expand Up @@ -244,6 +254,12 @@ macro_rules! socket_address {
Ok(Self {scion_addr, port })
}
}

impl AsRef<IsdAsn> for $name {
fn as_ref(&self) -> &IsdAsn {
self.scion_addr.as_ref()
}
}
};
}

Expand Down
27 changes: 25 additions & 2 deletions crates/scion-proto/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module contains types for SCION paths and metadata as well as encoding and decoding
//! functions.

use std::net::SocketAddr;
use std::{net::SocketAddr, ops::Deref};

use bytes::Bytes;
use scion_grpc::daemon::v1 as daemon_grpc;
Expand All @@ -27,7 +27,7 @@ pub mod epic;
pub use epic::EpicAuths;

/// A SCION end-to-end path with optional metadata.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub struct Path<T = Bytes> {
/// The raw bytes to be added as the path header to SCION dataplane packets.
pub dataplane_path: DataplanePath<T>,
Expand Down Expand Up @@ -125,6 +125,29 @@ impl Path<Bytes> {
}
}

impl From<Path<&mut [u8]>> for Path<Bytes> {
fn from(value: Path<&mut [u8]>) -> Self {
Self {
dataplane_path: value.dataplane_path.into(),
underlay_next_hop: value.underlay_next_hop,
isd_asn: value.isd_asn,
metadata: value.metadata,
}
}
}

impl<T> PartialEq for Path<T>
where
T: Deref<Target = [u8]>,
{
fn eq(&self, other: &Self) -> bool {
self.dataplane_path == other.dataplane_path
&& self.underlay_next_hop == other.underlay_next_hop
&& self.isd_asn == other.isd_asn
&& self.metadata == other.metadata
}
}
mlegner marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(test)]
mod tests {
use std::net::{IpAddr, Ipv4Addr};
Expand Down
39 changes: 37 additions & 2 deletions crates/scion-proto/src/path/dataplane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl From<u8> for PathType {
pub struct UnsupportedPathType(pub u8);

/// Dataplane path found in a SCION packet.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub enum DataplanePath<T = Bytes> {
/// The empty path type, used for intra-AS hops.
EmptyPath,
Expand Down Expand Up @@ -131,6 +131,17 @@ where
}
}

/// Reverse the path to the provided slice.
///
/// Unsupported path types are copied to the slice, as is.
pub fn reverse_to_slice<'b>(&self, buffer: &'b mut [u8]) -> DataplanePath<&'b mut [u8]> {
match self {
DataplanePath::EmptyPath => DataplanePath::EmptyPath,
DataplanePath::Standard(path) => DataplanePath::Standard(path.reverse_to_slice(buffer)),
DataplanePath::Unsupported { .. } => self.copy_to_slice(buffer),
}
}

/// Reverses the path.
pub fn to_reversed(&self) -> Result<DataplanePath, UnsupportedPathType> {
match self {
Expand Down Expand Up @@ -188,6 +199,30 @@ impl From<StandardPath> for DataplanePath {
}
}

impl<T, U> PartialEq<DataplanePath<U>> for DataplanePath<T>
where
T: Deref<Target = [u8]>,
U: Deref<Target = [u8]>,
{
fn eq(&self, other: &DataplanePath<U>) -> bool {
match (self, other) {
(Self::Standard(lhs), DataplanePath::Standard(rhs)) => lhs.raw() == rhs.raw(),
(
Self::Unsupported {
path_type: l_path_type,
bytes: l_bytes,
},
DataplanePath::Unsupported {
path_type: r_path_type,
bytes: r_bytes,
},
) => l_path_type == r_path_type && l_bytes.deref() == r_bytes.deref(),
(Self::EmptyPath, DataplanePath::EmptyPath) => true,
_ => false,
}
}
}

impl WireEncode for DataplanePath {
type Error = InadequateBufferSize;

Expand Down Expand Up @@ -275,7 +310,7 @@ mod tests {

#[test]
fn reverse_empty() {
let dataplane_path = DataplanePath::EmptyPath;
let dataplane_path = DataplanePath::<Bytes>::EmptyPath;
let reverse_path = dataplane_path.to_reversed().unwrap();
assert_eq!(dataplane_path, reverse_path);
assert_eq!(reverse_path.to_reversed().unwrap(), dataplane_path);
Expand Down
1 change: 1 addition & 0 deletions crates/scion/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ license = "Apache-2.0"
publish = false

[dependencies]
async-trait = "0.1.74"
bytes = "1.5.0"
chrono = { workspace = true, features = ["clock"] }
scion-grpc = { version = "0.1.0", path = "../scion-grpc" }
Expand Down
1 change: 1 addition & 0 deletions crates/scion/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

pub mod daemon;
pub mod dispatcher;
pub mod pan;
pub mod udp_socket;
142 changes: 142 additions & 0 deletions crates/scion/src/pan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//! Path aware networking socket and services.
mod datagram;
pub use datagram::{AsyncScionDatagram, PathAwareDatagram};

mod path_service;
pub use path_service::AsyncPathService;

mod error;
pub use error::{PathErrorKind, ReceiveError, SendError};

// use std::{
// borrow::Borrow,
// collections::{HashMap, VecDeque},
// marker::PhantomData,
// sync::Arc,
// };
//
// use bytes::Bytes;
// use scion_proto::{
// address::{IsdAsn, SocketAddr},
// path::Path,
// };

// TODO(jsmith):

// pub struct PathLookupError;
//
// /// Trait for retrieving paths to SCION ASes.
// #[async_trait::async_trait]
// pub trait PathService {
// /// Return a path to the specified AS.
// async fn path_to(&self, scion_as: IsdAsn) -> Result<Path, PathLookupError>;
//
// /// Propose a path to the service.
// ///
// /// The service may or may not choose to store the path.
// fn add_path(&self, path: &Path);
//
// /// Notify the service of a path-related SCMP message.
// fn on_scmp(&self, _args: ()) {
// todo!()
// }
// }
//
// #[derive(Debug, Default)]
// pub struct PathSet {
// paths: HashMap<IsdAsn, VecDeque<Path>>,
// }
//
// impl PathSet {
// pub fn new() -> Self {
// Self::default()
// }
// }
//
// #[async_trait::async_trait]
// impl PathService for PathSet {
// async fn path_to(&self, scion_as: IsdAsn) -> Result<Path, PathLookupError> {
// todo!()
// }
//
// fn add_path(&self, path: &Path) {
// todo!()
// }
// }
//
//
// impl<D, P> PathAwareDatagram<D, P>
// where
// D: ScionDatagramSocket,
// P: PathService,
// {
// pub fn new(datagram_socket: D, path_service: Arc<P>) -> Self {
// Self {
// datagram_socket,
// path_service,
// }
// }
//
// pub fn set_path_service(&mut self, path_service: Arc<P>) {
// self.path_service = path_service;
// }
//
// // pub fn set_path_service(&mut self, path_service: P) {
// // self.path_service = path_service;
// // }
// }
//
// // #[async_trait::async_trait]
// // impl<D, P> ScionDatagramSocket for PathAwareDatagram<D, P>
// // where
// // D: ScionDatagramSocket,
// // P: PathService,
// // {
// // async fn recv_with_path(&self, buffer: &mut [u8]) -> Result<(usize, Path), ReceiveError> {
// // self.datagram_socket.recv_with_path(buffer).await
// // }
// // // async fn recv_from_with_path(
// // // &self,
// // // buffer: &mut [u8],
// // // ) -> Result<(usize, SocketAddr, Path), Self::RecvErr>;
// // // async fn send_via(&self, payload: Bytes, path: &Path) -> Result<(), Self::SendErr>;
// // // async fn send_to_via(
// // // &self,
// // // payload: Bytes,
// // // destination: SocketAddr,
// // // path: &Path,
// // // ) -> Result<(), Self::SendErr>;
// // }
//
// #[cfg(test)]
// mod tests {
//
// use std::time::Duration;
//
// use tokio::net::UnixStream;
//
// use super::*;
// use crate::{dispatcher::DispatcherStream, udp_socket::UdpSocket};
//
// type TestResult<T = ()> = Result<T, Box<dyn std::error::Error>>;
//
// pub fn socket_from(source: SocketAddr) -> TestResult<(UdpSocket, DispatcherStream)> {
// let (inner, inner_remote) = UnixStream::pair()?;
// Ok((
// UdpSocket::new(DispatcherStream::new(inner), source),
// DispatcherStream::new(inner_remote),
// ))
// }
//
// // #[test]
// // fn sanity() -> TestResult {
// // let (socket, _) = socket_from("[1-ff00:0:110,3.3.3.3]:8080".parse()?)?;
// // let dgram_socket2 = PathAwareDatagram::new(socket, Arc::new(PathSet::new()));
// // dgram_socket2.hello();
// //
// // let (socket, _) = socket_from("[1-ff00:0:110,3.3.3.3]:8080".parse()?)?;
// // let dgram_socket2 = PathAwareDatagram::new(socket, Arc::new(PathSet::new()));
// // dgram_socket2.hello();
// // Ok(())
// // }
// }
Loading