Skip to content

Commit

Permalink
feat: add scion checksum computation
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcsmith committed Dec 1, 2023
1 parent e4385e7 commit 1787478
Show file tree
Hide file tree
Showing 12 changed files with 548 additions and 33 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ jobs:
- name: Run tests (including integration tests) and record coverage
run: >
DAEMON_ADDRESS=${{ steps.scion.outputs.daemon-address-as111 }}
cargo tarpaulin --workspace --skip-clean --all-targets --doc
cargo tarpaulin --workspace --skip-clean
--lib --bins --examples --tests --doc
--out html --out xml
--exclude-files "crates/scion-grpc/*"
--exclude-files "crates/**/tests/*"
--exclude-files "crates/**/benches/*"
-- --include-ignored
- name: Upload coverage report
Expand Down
3 changes: 3 additions & 0 deletions crates/scion-grpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ tonic = { workspace = true }

[build-dependencies]
tonic-build = { workspace = true }

[lib]
bench = false
7 changes: 7 additions & 0 deletions crates/scion-proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ tracing = { workspace = true }

[dev-dependencies]
prost-types = { workspace = true }
criterion = "0.5.1"
rand = "0.8.5"
rand_xorshift = "0.3.0"

[[bench]]
name = "checksum"
harness = false
57 changes: 57 additions & 0 deletions crates/scion-proto/benches/checksum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::{Fill, SeedableRng};
use rand_xorshift::XorShiftRng;
use scion_proto::packet::ChecksumDigest;

fn reference_checksum(data: &[u8]) -> u16 {
let mut cumsum = 0u32;
let mut i = 0usize;

let (data, leftover) = if data.len() % 2 == 0 {
(data, 0u8)
} else {
(&data[..data.len() - 1], data[data.len() - 1])
};

while i + 1 < data.len() {
cumsum += ((data[i] as u32) << 8) + (data[i + 1] as u32);
i += 2;
}
cumsum += (leftover as u32) << 8;

while cumsum > 0xffff {
cumsum = (cumsum >> 16) + (cumsum & 0xffff);
}

!(cumsum as u16)
}

fn bench_checksum(c: &mut Criterion) {
let mut group = c.benchmark_group("Checksum");
let mut data = Vec::new();
let mut rng = XorShiftRng::seed_from_u64(47);

for length in [512, 1024, 2048, 4096, 8192, 16384, 32768, 65536] {
let mut input_vec = vec![0u8; length];
input_vec.try_fill(&mut rng).unwrap();
data.push((length, input_vec));
}

for (length, vec) in data.iter() {
group.bench_with_input(
BenchmarkId::new("Reference", length),
vec.as_slice(),
|b, data| b.iter(|| assert_ne!(0, reference_checksum(data))),
);
group.bench_with_input(
BenchmarkId::new("Unsafe", length),
vec.as_slice(),
|b, data| b.iter(|| assert_ne!(0, ChecksumDigest::new().add_slice(data).checksum())),
);
}

group.finish()
}

criterion_group!(benches, bench_checksum);
criterion_main!(benches);
1 change: 1 addition & 0 deletions crates/scion-proto/src/address/asn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::{error::AddressKind, AddressParseError};

/// A SCION autonomous system (AS) number
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Asn(u64);

impl Asn {
Expand Down
1 change: 1 addition & 0 deletions crates/scion-proto/src/address/isd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use super::{error::AddressKind, AddressParseError};
/// See formatting and allocations here:
/// <https://github.com/scionproto/scion/wiki/ISD-and-AS-numbering#isd-numbers>
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Isd(u16);

impl Isd {
Expand Down
1 change: 1 addition & 0 deletions crates/scion-proto/src/address/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::{error::AddressKind, AddressParseError, Host, HostAddress, HostType};
/// both represent the anycast service address ServiceAddress::CONTROL. The
/// corresponding multicast service address would be CS_M.
#[derive(Eq, PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ServiceAddress(pub u16);

impl ServiceAddress {
Expand Down
15 changes: 14 additions & 1 deletion crates/scion-proto/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,26 @@ pub use address_header::{AddressHeader, RawHostAddress};
mod path_header;
pub use path_header::DataplanePath;

mod checksum;
pub use checksum::ChecksumDigest;

/// Instances of an object associated with both a source and destination endpoint.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub struct ByEndpoint<T> {
pub destination: T,
pub source: T,
}

impl<T: Clone> ByEndpoint<T> {
/// Create a new instance where both the source and destination have the same value.
pub fn with_cloned(source_and_destination: T) -> Self {
Self {
destination: source_and_destination.clone(),
source: source_and_destination,
}
}
}

/// A SCION network packet.
#[allow(unused)]
pub struct ScionPacket {
Expand Down
72 changes: 51 additions & 21 deletions crates/scion-proto/src/packet/address_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ pub struct AddressHeader {
pub host: ByEndpoint<MaybeEncoded<Host, (AddressInfo, RawHostAddress)>>,
}

impl AddressHeader {
/// Creates a new AddressHeader with the specified ISD-AS numbers and hosts.
pub fn new(ia: ByEndpoint<IsdAsn>, host: ByEndpoint<Host>) -> Self {
Self {
ia,
host: ByEndpoint {
destination: MaybeEncoded::Decoded(host.destination),
source: MaybeEncoded::Decoded(host.source),
},
}
}
}

impl<T: Buf> WireDecodeWithContext<T> for AddressHeader {
type Error = DecodeError;
type Context = ByEndpoint<AddressInfo>;
Expand Down Expand Up @@ -60,39 +73,56 @@ impl WireEncode for AddressHeader {
buffer.put_u64(self.ia.destination.into());
buffer.put_u64(self.ia.source.into());

encode_host(self.host.destination, buffer)?;
encode_host(self.host.source, buffer)
try_encode_host(self.host.destination, buffer)?;
try_encode_host(self.host.source, buffer)?;

Ok(())
}
}

#[inline]
fn get_encoded_length(host: &MaybeEncoded<Host, (AddressInfo, RawHostAddress)>) -> usize {
match host {
MaybeEncoded::Decoded(host) => AddressInfo::for_host(host).address_length(),
MaybeEncoded::Encoded((info, _)) => info.address_length(),
}
}

fn encode_host(
fn try_encode_host(
host: MaybeEncoded<Host, (AddressInfo, RawHostAddress)>,
buffer: &mut impl BufMut,
) -> Result<(), InadequateBufferSize> {
match host {
MaybeEncoded::Decoded(host_addr) => {
if buffer.remaining_mut() < AddressInfo::for_host(&host_addr).address_length() {
return Err(InadequateBufferSize);
}
) -> Result<usize, InadequateBufferSize> {
if buffer.remaining_mut() < get_encoded_length(&host) {
Err(InadequateBufferSize)
} else {
Ok(encode_host(host, buffer))
}
}

match host_addr {
Host::Ip(std::net::IpAddr::V4(addr)) => buffer.put_slice(&addr.octets()),
Host::Ip(std::net::IpAddr::V6(addr)) => buffer.put_slice(&addr.octets()),
Host::Svc(addr) => {
buffer.put_u16(addr.into());
buffer.put_u16(0);
}
/// Encodes the host into the buffer.
///
/// Panics if the buffer has insufficient capacity.
pub(crate) fn encode_host(
host: MaybeEncoded<Host, (AddressInfo, RawHostAddress)>,
buffer: &mut impl BufMut,
) -> usize {
let initial_length = buffer.remaining_mut();

match host {
MaybeEncoded::Decoded(host_addr) => match host_addr {
Host::Ip(std::net::IpAddr::V4(addr)) => buffer.put_slice(&addr.octets()),
Host::Ip(std::net::IpAddr::V6(addr)) => buffer.put_slice(&addr.octets()),
Host::Svc(addr) => {
buffer.put_u16(addr.into());
buffer.put_u16(0);
}
}
},
MaybeEncoded::Encoded((addr_info, encoded_host)) => {
if buffer.remaining_mut() < addr_info.address_length() {
return Err(InadequateBufferSize);
}
buffer.put_slice(&encoded_host[..addr_info.address_length()]);
}
}

Ok(())
initial_length - buffer.remaining_mut()
}

fn maybe_decode_host<T>(
Expand Down
Loading

0 comments on commit 1787478

Please sign in to comment.