#![allow(
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
reason = "M175: DSCP byte-level socket option packing — 8-bit values by spec"
)]
use std::os::fd::AsRawFd;
pub(crate) fn apply_dscp<S: AsRawFd>(socket: &S, dscp: u8, is_ipv6: bool) {
if dscp == 0 {
return;
}
let tos = libc::c_int::from(dscp << 2); let fd = socket.as_raw_fd();
let result = unsafe {
if is_ipv6 {
libc::setsockopt(
fd,
libc::IPPROTO_IPV6,
libc::IPV6_TCLASS,
(&raw const tos).cast::<libc::c_void>(),
std::mem::size_of::<libc::c_int>() as libc::socklen_t,
)
} else {
libc::setsockopt(
fd,
libc::IPPROTO_IP,
libc::IP_TOS,
(&raw const tos).cast::<libc::c_void>(),
std::mem::size_of::<libc::c_int>() as libc::socklen_t,
)
}
};
if result != 0 {
tracing::debug!(
dscp,
%is_ipv6,
"failed to set DSCP: {}",
std::io::Error::last_os_error()
);
}
}
pub(crate) fn apply_dscp_listener(listener: &tokio::net::TcpListener, dscp: u8) {
if dscp == 0 {
return;
}
let addr = listener.local_addr().ok();
let is_ipv6 = addr.is_some_and(|a| a.is_ipv6());
apply_dscp(listener, dscp, is_ipv6);
}
pub(crate) fn apply_dscp_tcp(stream: &tokio::net::TcpStream, dscp: u8) {
if dscp == 0 {
return;
}
let addr = stream.peer_addr().ok();
let is_ipv6 = addr.is_some_and(|a| a.is_ipv6());
apply_dscp(stream, dscp, is_ipv6);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dscp_zero_is_noop() {
let sock = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
apply_dscp(&sock, 0, false);
}
#[test]
fn dscp_ipv4_succeeds() {
let sock = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
apply_dscp(&sock, 0x08, false); let fd = sock.as_raw_fd();
let mut tos: libc::c_int = 0;
let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
let r = unsafe {
libc::getsockopt(
fd,
libc::IPPROTO_IP,
libc::IP_TOS,
(&raw mut tos).cast::<libc::c_void>(),
&raw mut len,
)
};
assert_eq!(r, 0);
assert_eq!(tos, 0x20); }
#[test]
fn dscp_ipv6_succeeds() {
let sock = std::net::TcpListener::bind("[::1]:0").unwrap();
apply_dscp(&sock, 0x08, true); let fd = sock.as_raw_fd();
let mut tclass: libc::c_int = 0;
let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
let r = unsafe {
libc::getsockopt(
fd,
libc::IPPROTO_IPV6,
libc::IPV6_TCLASS,
(&raw mut tclass).cast::<libc::c_void>(),
&raw mut len,
)
};
assert_eq!(r, 0);
assert_eq!(tclass, 0x20); }
#[test]
fn dscp_ef_value() {
let sock = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
apply_dscp(&sock, 0x2E, false); let fd = sock.as_raw_fd();
let mut tos: libc::c_int = 0;
let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
let r = unsafe {
libc::getsockopt(
fd,
libc::IPPROTO_IP,
libc::IP_TOS,
(&raw mut tos).cast::<libc::c_void>(),
&raw mut len,
)
};
assert_eq!(r, 0);
assert_eq!(tos, 0xB8); }
}