Skip to content
Open
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
15 changes: 15 additions & 0 deletions docs/reference/qos-dscp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# DSCP (IP_TOS) QoS Marking

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Move public reference docs into the website tree

This new user-facing reference page is added under top-level docs/, which this repo uses for developer documentation, while the public Vector reference pages live under website/content/en/docs/reference with CUE-generated component data. Because nothing links or builds docs/reference/qos-dscp.md, the new option page will not appear on vector.dev even after the feature is wired. Please move or duplicate this content in the website reference documentation path.

Useful? React with 👍 / 👎.


Vector can optionally set the IP_TOS (DSCP) byte on sockets created by sources and sinks.

Configure using DSCP names or numeric TOS values:

```toml
[sources.my_tcp]
# ... other settings
ip_tos = "EF" # or "CS5", "AF21", etc.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add real config wiring before documenting ip_tos

The advertised ip_tos key is not actually accepted or applied: this commit only adds standalone files, while src/net.rs does not declare mod qos, src/sources/util/net/tcp/mod.rs does not declare/call qos, and rg "ip_tos|apply_qos|parse_ip_tos" finds no config fields or call sites outside these new files/docs. Cargo will not build the helpers or run their tests, so configurations using this key cannot mark sockets. Please wire the field through the source/sink configs and apply it on connect/accept before documenting it.

Useful? React with 👍 / 👎.

# ip_tos = 184 # numeric TOS byte
```

Supported names: CS0..CS7, AF11..AF43, EF. Names map to DSCP codes; the TOS byte is DSCP<<2 (ECN bits 0).
On unsupported platforms the setting is ignored with a warning.
102 changes: 102 additions & 0 deletions src/net/qos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! DSCP (IP_TOS) QoS helpers: parse names and set/get socket TOS.
use std::io;
#[cfg(any(unix, windows))]
use socket2::SockRef;
use std::net::{TcpStream, UdpSocket};

/// Parse a DSCP name (CS0-CS7, AF11..AF43, EF) into the DSCP 6-bit code.
fn parse_dscp_code(name: &str) -> Option<u8> {
let s = name.trim();
if s.is_empty() { return None; }
// Numeric value (decimal or 0xHEX) as full TOS byte (0-255)
if let Some(stripped) = s.strip_prefix("0x") { if let Ok(v) = u8::from_str_radix(stripped, 16) { return Some(v >> 2); } }
if let Ok(v) = s.parse::<u8>() { return Some(v >> 2); }
let u = s.to_ascii_uppercase();
if u == "EF" { return Some(46); }
if let Some(n) = u.strip_prefix("CS") { if let Ok(c) = n.parse::<u8>() { if c <= 7 { return Some(c * 8); } } }
if let Some(af) = u.strip_prefix("AF") {
let bytes = af.as_bytes();
if bytes.len() == 2 {
let c = bytes[0];
let d = bytes[1];
if (b'1'..=b'4').contains(&c) && (b'1'..=b'3').contains(&d) {
let class = (c - b'0') as u8; // 1..4
let drop = (d - b'0') as u8; // 1..3
// Map per RFC 2597
let code = match (class, drop) {
(1,1)=>10,(1,2)=>12,(1,3)=>14,
(2,1)=>18,(2,2)=>20,(2,3)=>22,
(3,1)=>26,(3,2)=>28,(3,3)=>30,
(4,1)=>34,(4,2)=>36,(4,3)=>38,
_=>return None,
};
return Some(code);
}
}
}
None
}

/// Parse user input into a final TOS byte (DSCP<<2), leaving ECN bits zero.
pub fn parse_ip_tos(input: &str) -> Option<u8> {
let s = input.trim();
if s.is_empty() { return None; }
// If numeric, accept as full TOS byte (0-255)
if let Some(stripped) = s.strip_prefix("0x") { if let Ok(v) = u8::from_str_radix(stripped, 16) { return Some(v); } }
if let Ok(v) = s.parse::<u8>() { return Some(v); }
parse_dscp_code(s).map(|code| code << 2)
}

/// Set IP_TOS on a TCP stream if supported; otherwise return Ok(()) and let caller log.
pub fn set_stream_tos(stream: &TcpStream, tos: u8) -> io::Result<()> {
#[cfg(any(unix, windows))]
{
let sref = SockRef::from(stream);
return sref.set_tos(tos);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle IPv6 traffic class as well

When this helper is wired to an IPv6 source or sink, SockRef::set_tos only sets the IPv4 IP_TOS option, while IPv6 packets carry DSCP in the IPv6 traffic-class field. Vector accepts IPv6 socket addresses, so IPv6 users would either get an error or a connection whose packets are not marked despite ip_tos being configured. Please set the IPv6 traffic class too, or reject/document IPv4-only support.

Useful? React with 👍 / 👎.

}
#[allow(unreachable_code)]
Ok(())
}

/// Set IP_TOS on a UDP socket if supported; otherwise Ok(()) on unsupported platforms.
pub fn set_udp_tos(sock: &UdpSocket, tos: u8) -> io::Result<()> {
#[cfg(any(unix, windows))]
{
let sref = SockRef::from(sock);
return sref.set_tos(tos);
}
#[allow(unreachable_code)]
Ok(())
}

/// Get current TOS if supported; returns None on unsupported platforms or error.
pub fn get_udp_tos(sock: &UdpSocket) -> Option<u8> {
#[cfg(any(unix, windows))]
{
let sref = SockRef::from(sock);
return sref.tos().ok().map(|v| v as u8);
}
None
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parse_names_to_tos() {
assert_eq!(parse_ip_tos("CS0"), Some(0));
assert_eq!(parse_ip_tos("CS3"), Some((24)<<2));
assert_eq!(parse_ip_tos("EF"), Some(46<<2));
assert_eq!(parse_ip_tos("AF21"), Some(18<<2));
assert_eq!(parse_ip_tos("0xB8"), Some(0xB8));
assert_eq!(parse_ip_tos("184"), Some(184));
}

#[test]
fn parse_invalid() {
assert_eq!(parse_ip_tos(""), None);
assert_eq!(parse_ip_tos("AF00"), None);
assert_eq!(parse_ip_tos("CS9"), None);
}
}
11 changes: 11 additions & 0 deletions src/sources/util/net/tcp/qos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! TCP QoS helpers to apply DSCP TOS on newly created sockets.
use std::net::TcpStream;
use crate::net::qos::set_stream_tos;

pub fn apply_qos(stream: &TcpStream, tos: Option<u8>) {
if let Some(t) = tos {
if let Err(e) = set_stream_tos(stream, t) {
let _ = e;
Comment on lines +7 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Warn or propagate TOS-setting failures

When set_stream_tos fails for platform, permission, or socket-family reasons, this helper discards the error with let _ = e and returns (). That makes QoS silently absent even though the new reference text says unsupported platforms are ignored with a warning, so operators have no signal that DSCP marking did not take effect. Please emit a warning here or return the error to the caller.

Useful? React with 👍 / 👎.

}
}
}
Loading