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

refactor(s2n-quic-platform): move pktinfo checks to separate modules #2124

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions quic/s2n-quic-platform/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ type c_int = std::os::raw::c_int;

pub mod gro;
pub mod gso;
pub mod pktinfo;
pub mod pktinfo_v4;
pub mod pktinfo_v6;
pub mod tos;
pub mod tos_v4;
pub mod tos_v6;

pub use gso::Gso;
4 changes: 4 additions & 0 deletions quic/s2n-quic-platform/src/features/pktinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

pub const IS_SUPPORTED: bool = super::pktinfo_v4::IS_SUPPORTED || super::pktinfo_v6::IS_SUPPORTED;
105 changes: 105 additions & 0 deletions quic/s2n-quic-platform/src/features/pktinfo_v4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::c_int;
use s2n_quic_core::inet::IpV4Address;

#[cfg(s2n_quic_platform_pktinfo)]
mod pktinfo_enabled {
use super::*;
use crate::message::cmsg;
use libc::{IPPROTO_IP, IP_PKTINFO};

pub const LEVEL: Option<c_int> = Some(IPPROTO_IP as _);
pub const TYPE: Option<c_int> = Some(IP_PKTINFO as _);
pub const SOCKOPT: Option<(c_int, c_int)> = Some((IPPROTO_IP as _, IP_PKTINFO as _));
pub const CMSG_SPACE: usize = crate::message::cmsg::size_of_cmsg::<Cmsg>();

pub type Cmsg = libc::in_pktinfo;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
level == IPPROTO_IP as c_int && ty == IP_PKTINFO as c_int
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
#[inline]
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV4Address, u32)> {
let pkt_info = cmsg::decode::value_from_bytes::<Cmsg>(bytes)?;

// read from both fields in case only one is set and not the other
//
// from https://man7.org/linux/man-pages/man7/ip.7.html:
//
// > ipi_spec_dst is the local address
// > of the packet and ipi_addr is the destination address in
// > the packet header.
let local_address = match (pkt_info.ipi_addr.s_addr, pkt_info.ipi_spec_dst.s_addr) {
(0, v) => v.to_ne_bytes(),
(v, _) => v.to_ne_bytes(),
};

let address = IpV4Address::new(local_address);
let interface = pkt_info.ipi_ifindex as _;

Some((address, interface))
}

#[inline]
pub fn encode(addr: &IpV4Address, local_interface: Option<u32>) -> Cmsg {
let mut pkt_info = unsafe { core::mem::zeroed::<Cmsg>() };
pkt_info.ipi_spec_dst.s_addr = u32::from_ne_bytes((*addr).into());
if let Some(interface) = local_interface {
pkt_info.ipi_ifindex = interface as _;
}
pkt_info
}
}

#[cfg(any(not(s2n_quic_platform_pktinfo), test))]
mod pktinfo_disabled {
#![cfg_attr(test, allow(dead_code))]
use super::*;

pub const LEVEL: Option<c_int> = None;
pub const TYPE: Option<c_int> = None;
pub const SOCKOPT: Option<(c_int, c_int)> = None;
pub const CMSG_SPACE: usize = 0;

pub type Cmsg = c_int;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
let _ = level;
let _ = ty;
false
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV4Address, u32)> {
let _ = bytes;
None
}

#[inline]
pub fn encode(addr: &IpV4Address, local_interface: Option<u32>) -> Cmsg {
let _ = addr;
let _ = local_interface;
unimplemented!("this platform does not support pktinfo")
}
}

mod pktinfo_impl {
#[cfg(not(s2n_quic_platform_pktinfo))]
pub use super::pktinfo_disabled::*;
#[cfg(s2n_quic_platform_pktinfo)]
pub use super::pktinfo_enabled::*;
}

pub use pktinfo_impl::*;

pub const IS_SUPPORTED: bool = cfg!(s2n_quic_platform_pktinfo);
94 changes: 94 additions & 0 deletions quic/s2n-quic-platform/src/features/pktinfo_v6.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::c_int;
use s2n_quic_core::inet::IpV6Address;

#[cfg(s2n_quic_platform_pktinfo)]
mod pktinfo_enabled {
use super::*;
use crate::message::cmsg;
use libc::{IPPROTO_IPV6, IPV6_PKTINFO, IPV6_RECVPKTINFO};

pub const LEVEL: Option<c_int> = Some(IPPROTO_IPV6 as _);
pub const TYPE: Option<c_int> = Some(IPV6_PKTINFO as _);
pub const SOCKOPT: Option<(c_int, c_int)> = Some((IPPROTO_IPV6 as _, IPV6_RECVPKTINFO));
pub const CMSG_SPACE: usize = crate::message::cmsg::size_of_cmsg::<Cmsg>();

pub type Cmsg = libc::in6_pktinfo;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
level == IPPROTO_IPV6 as c_int && ty == IPV6_PKTINFO as c_int
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV6Address, u32)> {
let pkt_info = cmsg::decode::value_from_bytes::<Cmsg>(bytes)?;

let local_address = pkt_info.ipi6_addr.s6_addr;

let address = IpV6Address::new(local_address);
let interface = pkt_info.ipi6_ifindex as _;

Some((address, interface))
}

#[inline]
pub fn encode(addr: &IpV6Address, local_interface: Option<u32>) -> Cmsg {
let mut pkt_info = unsafe { core::mem::zeroed::<Cmsg>() };
pkt_info.ipi6_addr.s6_addr = (*addr).into();
if let Some(interface) = local_interface {
pkt_info.ipi6_ifindex = interface as _;
}
pkt_info
}
}

#[cfg(any(not(s2n_quic_platform_pktinfo), test))]
mod pktinfo_disabled {
#![cfg_attr(test, allow(dead_code))]
use super::*;

pub const LEVEL: Option<c_int> = None;
pub const TYPE: Option<c_int> = None;
pub const SOCKOPT: Option<(c_int, c_int)> = None;
pub const CMSG_SPACE: usize = 0;

pub type Cmsg = c_int;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
let _ = level;
let _ = ty;
false
}

/// # Safety
///
/// * The provided bytes must be aligned to `cmsghdr`
pub unsafe fn decode(bytes: &[u8]) -> Option<(IpV6Address, u32)> {
let _ = bytes;
None
}

#[inline]
pub fn encode(addr: &IpV6Address, local_interface: Option<u32>) -> Cmsg {
let _ = addr;
let _ = local_interface;
unimplemented!("this platform does not support pktinfo")
}
}

mod pktinfo_impl {
#[cfg(not(s2n_quic_platform_pktinfo))]
pub use super::pktinfo_disabled::*;
#[cfg(s2n_quic_platform_pktinfo)]
pub use super::pktinfo_enabled::*;
}

pub use pktinfo_impl::*;

pub const IS_SUPPORTED: bool = cfg!(s2n_quic_platform_pktinfo);
23 changes: 23 additions & 0 deletions quic/s2n-quic-platform/src/features/tos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::c_int;
use s2n_quic_core::inet::ExplicitCongestionNotification;

pub const IS_SUPPORTED: bool = super::tos_v4::IS_SUPPORTED || super::tos_v6::IS_SUPPORTED;

#[inline]
pub const fn is_match(level: c_int, ty: c_int) -> bool {
super::tos_v4::is_match(level, ty) || super::tos_v6::is_match(level, ty)
}

#[inline]
pub fn decode(bytes: &[u8]) -> Option<ExplicitCongestionNotification> {
let value = match bytes.len() {
1 => bytes[0],
4 => u32::from_ne_bytes(bytes.try_into().unwrap()) as u8,
_ => return None,
};

Some(ExplicitCongestionNotification::new(value))
}
Loading
Loading