From d5dead758026330f050ad84a9ba2e0a6977cfb98 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Mon, 22 Jan 2024 14:43:25 +0200 Subject: [PATCH] Move IpTos things into their own source file --- neqo-common/src/datagram.rs | 147 +------------------ neqo-common/src/lib.rs | 4 +- neqo-common/src/tos.rs | 276 ++++++++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+), 146 deletions(-) create mode 100644 neqo-common/src/tos.rs diff --git a/neqo-common/src/datagram.rs b/neqo-common/src/datagram.rs index 4b6b888137..c971438907 100644 --- a/neqo-common/src/datagram.rs +++ b/neqo-common/src/datagram.rs @@ -7,106 +7,7 @@ use std::net::SocketAddr; use std::ops::Deref; -use enum_map::Enum; - -use crate::hex_with_len; - -// ECN (Explicit Congestion Notification) codepoints mapped to the -// lower 2 bits of the TOS field. -// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml -#[derive(Copy, Clone, PartialEq, Eq, Enum, Default)] -#[repr(u8)] -pub enum IpTosEcn { - #[default] - NotEct = 0b00, // Not-ECT, Not ECN-Capable Transport, [RFC3168] - Ect1 = 0b01, // ECT(1), ECN-Capable Transport(1), [RFC8311][RFC9331] - Ect0 = 0b10, // ECT(0), ECN-Capable Transport(0), [RFC3168] - Ce = 0b11, // CE, Congestion Experienced, [RFC3168] -} - -impl std::fmt::Debug for IpTosEcn { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - IpTosEcn::NotEct => f.write_str("Not-ECT"), - IpTosEcn::Ect1 => f.write_str("ECT(1)"), - IpTosEcn::Ect0 => f.write_str("ECT(0)"), - IpTosEcn::Ce => f.write_str("CE"), - } - } -} - -// DiffServ Codepoints, mapped to the upper six bits of the TOS field. -// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml -#[derive(Copy, Clone, PartialEq, Eq, Enum, Default)] -#[repr(u8)] -pub enum IpTosDscp { - #[default] - Cs0 = 0b0000_0000, // Class Selector 0, [RFC2474] - Cs1 = 0b0010_0000, // Class Selector 1, [RFC2474] - Cs2 = 0b0100_0000, // Class Selector 2, [RFC2474] - Cs3 = 0b0110_0000, // Class Selector 3, [RFC2474] - Cs4 = 0b1000_0000, // Class Selector 4, [RFC2474] - Cs5 = 0b1010_0000, // Class Selector 5, [RFC2474] - Cs6 = 0b1100_0000, // Class Selector 6, [RFC2474] - Cs7 = 0b1110_0000, // Class Selector 7, [RFC2474] - Af11 = 0b0010_1000, // Assured Forwarding 11, [RFC2597] - Af12 = 0b0011_0000, // Assured Forwarding 12, [RFC2597] - Af13 = 0b0011_1000, // Assured Forwarding 13, [RFC2597] - Af21 = 0b0100_1000, // Assured Forwarding 21, [RFC2597] - Af22 = 0b0101_0000, // Assured Forwarding 22, [RFC2597] - Af23 = 0b0101_1000, // Assured Forwarding 23, [RFC2597] - Af31 = 0b0110_1000, // Assured Forwarding 31, [RFC2597] - Af32 = 0b0111_0000, // Assured Forwarding 32, [RFC2597] - Af33 = 0b0111_1000, // Assured Forwarding 33, [RFC2597] - Af41 = 0b1000_1000, // Assured Forwarding 41, [RFC2597] - Af42 = 0b1001_0000, // Assured Forwarding 42, [RFC2597] - Af43 = 0b1001_1000, // Assured Forwarding 43, [RFC2597] - Ef = 0b1011_1000, // Expedited Forwarding, [RFC3246] - VoiceAdmit = 0b1011_0000, // Capacity-Admitted Traffic, [RFC5865] - Le = 0b0000_0100, // Lower-Effort, [RFC8622] -} - -impl std::fmt::Debug for IpTosDscp { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - IpTosDscp::Cs0 => f.write_str("CS0"), - IpTosDscp::Cs1 => f.write_str("CS1"), - IpTosDscp::Cs2 => f.write_str("CS2"), - IpTosDscp::Cs3 => f.write_str("CS3"), - IpTosDscp::Cs4 => f.write_str("CS4"), - IpTosDscp::Cs5 => f.write_str("CS5"), - IpTosDscp::Cs6 => f.write_str("CS6"), - IpTosDscp::Cs7 => f.write_str("CS7"), - IpTosDscp::Af11 => f.write_str("AF11"), - IpTosDscp::Af12 => f.write_str("AF12"), - IpTosDscp::Af13 => f.write_str("AF13"), - IpTosDscp::Af21 => f.write_str("AF21"), - IpTosDscp::Af22 => f.write_str("AF22"), - IpTosDscp::Af23 => f.write_str("AF23"), - IpTosDscp::Af31 => f.write_str("AF31"), - IpTosDscp::Af32 => f.write_str("AF32"), - IpTosDscp::Af33 => f.write_str("AF33"), - IpTosDscp::Af41 => f.write_str("AF41"), - IpTosDscp::Af42 => f.write_str("AF42"), - IpTosDscp::Af43 => f.write_str("AF43"), - IpTosDscp::Ef => f.write_str("EF"), - IpTosDscp::VoiceAdmit => f.write_str("VOICE-ADMIT"), - IpTosDscp::Le => f.write_str("LE"), - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Default)] -pub struct IpTos((IpTosDscp, IpTosEcn)); - -impl std::fmt::Debug for IpTos { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_tuple("IpTos") - .field(&self.0 .0) - .field(&self.0 .1) - .finish() - } -} +use crate::{hex_with_len, IpTos}; #[derive(Clone, PartialEq, Eq)] pub struct Datagram { @@ -180,56 +81,12 @@ impl std::fmt::Debug for Datagram { #[cfg(test)] use test_fixture::datagram; -#[test] -fn ip_tos_ecn_fmt() { - assert_eq!(format!("{:?}", IpTosEcn::NotEct), "Not-ECT"); - assert_eq!(format!("{:?}", IpTosEcn::Ect1), "ECT(1)"); - assert_eq!(format!("{:?}", IpTosEcn::Ect0), "ECT(0)"); - assert_eq!(format!("{:?}", IpTosEcn::Ce), "CE"); -} - -#[test] -fn ip_tos_dscp_fmt() { - assert_eq!(format!("{:?}", IpTosDscp::Cs0), "CS0"); - assert_eq!(format!("{:?}", IpTosDscp::Cs1), "CS1"); - assert_eq!(format!("{:?}", IpTosDscp::Cs2), "CS2"); - assert_eq!(format!("{:?}", IpTosDscp::Cs3), "CS3"); - assert_eq!(format!("{:?}", IpTosDscp::Cs4), "CS4"); - assert_eq!(format!("{:?}", IpTosDscp::Cs5), "CS5"); - assert_eq!(format!("{:?}", IpTosDscp::Cs6), "CS6"); - assert_eq!(format!("{:?}", IpTosDscp::Cs7), "CS7"); - assert_eq!(format!("{:?}", IpTosDscp::Af11), "AF11"); - assert_eq!(format!("{:?}", IpTosDscp::Af12), "AF12"); - assert_eq!(format!("{:?}", IpTosDscp::Af13), "AF13"); - assert_eq!(format!("{:?}", IpTosDscp::Af21), "AF21"); - assert_eq!(format!("{:?}", IpTosDscp::Af22), "AF22"); - assert_eq!(format!("{:?}", IpTosDscp::Af23), "AF23"); - assert_eq!(format!("{:?}", IpTosDscp::Af31), "AF31"); - assert_eq!(format!("{:?}", IpTosDscp::Af32), "AF32"); - assert_eq!(format!("{:?}", IpTosDscp::Af33), "AF33"); - assert_eq!(format!("{:?}", IpTosDscp::Af41), "AF41"); - assert_eq!(format!("{:?}", IpTosDscp::Af42), "AF42"); - assert_eq!(format!("{:?}", IpTosDscp::Af43), "AF43"); - assert_eq!(format!("{:?}", IpTosDscp::Ef), "EF"); - assert_eq!(format!("{:?}", IpTosDscp::VoiceAdmit), "VOICE-ADMIT"); - assert_eq!(format!("{:?}", IpTosDscp::Le), "LE"); -} - -#[test] -fn ip_tos_debug_fmt() { - let ip_tos = IpTos((IpTosDscp::Cs0, IpTosEcn::NotEct)); - assert_eq!(format!("{ip_tos:?}"), "IpTos(CS0, Not-ECT)"); - - let ip_tos = IpTos((IpTosDscp::Af11, IpTosEcn::Ce)); - assert_eq!(format!("{ip_tos:?}"), "IpTos(AF11, CE)"); -} - #[test] fn fmt_datagram() { let d = datagram([0; 1].to_vec()); assert_eq!( format!("{d:?}"), - "Datagram IpTos(CS0, Not-ECT) TTL Some(128) [fe80::1]:443->[fe80::1]:443: [1]: 00" + "Datagram IpTos { dscp: Cs0, ecn: NotEct } TTL Some(128) [fe80::1]:443->[fe80::1]:443: [1]: 00" .to_string() ); } diff --git a/neqo-common/src/lib.rs b/neqo-common/src/lib.rs index 46579503d4..202f39e0fb 100644 --- a/neqo-common/src/lib.rs +++ b/neqo-common/src/lib.rs @@ -16,13 +16,15 @@ mod incrdecoder; pub mod log; pub mod qlog; pub mod timer; +pub mod tos; pub use self::codec::{Decoder, Encoder}; -pub use self::datagram::{Datagram, IpTos, IpTosDscp, IpTosEcn}; +pub use self::datagram::Datagram; pub use self::header::Header; pub use self::incrdecoder::{ IncrementalDecoderBuffer, IncrementalDecoderIgnore, IncrementalDecoderUint, }; +pub use self::tos::{IpTos, IpTosDscp, IpTosEcn}; use std::fmt::Write; diff --git a/neqo-common/src/tos.rs b/neqo-common/src/tos.rs new file mode 100644 index 0000000000..54aeefc63c --- /dev/null +++ b/neqo-common/src/tos.rs @@ -0,0 +1,276 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use enum_map::Enum; + +/// ECN (Explicit Congestion Notification) codepoints mapped to the +/// lower 2 bits of the TOS field. +/// +#[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug)] +#[repr(u8)] +pub enum IpTosEcn { + #[default] + /// Not-ECT, Not ECN-Capable Transport, [RFC3168] + NotEct = 0b00, + + /// ECT(1), ECN-Capable Transport(1), [RFC8311][RFC9331] + Ect1 = 0b01, + + /// ECT(0), ECN-Capable Transport(0), [RFC3168] + Ect0 = 0b10, + + /// CE, Congestion Experienced, [RFC3168] + Ce = 0b11, +} + +impl From for u8 { + fn from(v: IpTosEcn) -> Self { + v as u8 + } +} + +impl From for IpTosEcn { + fn from(v: u8) -> Self { + match v & 0b11 { + 0b00 => IpTosEcn::NotEct, + 0b01 => IpTosEcn::Ect1, + 0b10 => IpTosEcn::Ect0, + 0b11 => IpTosEcn::Ce, + _ => unreachable!(), + } + } +} + +/// Diffserv Codepoints, mapped to the upper six bits of the TOS field. +/// +#[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug)] +#[repr(u8)] +pub enum IpTosDscp { + #[default] + /// Class Selector 0, [RFC2474] + Cs0 = 0b0000_0000, + + /// Class Selector 1, [RFC2474] + Cs1 = 0b0010_0000, + + /// Class Selector 2, [RFC2474] + Cs2 = 0b0100_0000, + + /// Class Selector 3, [RFC2474] + Cs3 = 0b0110_0000, + + /// Class Selector 4, [RFC2474] + Cs4 = 0b1000_0000, + + /// Class Selector 5, [RFC2474] + Cs5 = 0b1010_0000, + + /// Class Selector 6, [RFC2474] + Cs6 = 0b1100_0000, + + /// Class Selector 7, [RFC2474] + Cs7 = 0b1110_0000, + + /// Assured Forwarding 11, [RFC2597] + Af11 = 0b0010_1000, + + /// Assured Forwarding 12, [RFC2597] + Af12 = 0b0011_0000, + + /// Assured Forwarding 13, [RFC2597] + Af13 = 0b0011_1000, + + /// Assured Forwarding 21, [RFC2597] + Af21 = 0b0100_1000, + + /// Assured Forwarding 22, [RFC2597] + Af22 = 0b0101_0000, + + /// Assured Forwarding 23, [RFC2597] + Af23 = 0b0101_1000, + + /// Assured Forwarding 31, [RFC2597] + Af31 = 0b0110_1000, + + /// Assured Forwarding 32, [RFC2597] + Af32 = 0b0111_0000, + + /// Assured Forwarding 33, [RFC2597] + Af33 = 0b0111_1000, + + /// Assured Forwarding 41, [RFC2597] + Af41 = 0b1000_1000, + + /// Assured Forwarding 42, [RFC2597] + Af42 = 0b1001_0000, + + /// Assured Forwarding 43, [RFC2597] + Af43 = 0b1001_1000, + + /// Expedited Forwarding, [RFC3246] + Ef = 0b1011_1000, + + /// Capacity-Admitted Traffic, [RFC5865] + VoiceAdmit = 0b1011_0000, + + /// Lower-Effort, [RFC8622] + Le = 0b0000_0100, +} + +impl From for u8 { + fn from(v: IpTosDscp) -> Self { + v as u8 + } +} + +impl From for IpTosDscp { + fn from(v: u8) -> Self { + match v & 0b1111_1100 { + 0b0000_0000 => IpTosDscp::Cs0, + 0b0010_0000 => IpTosDscp::Cs1, + 0b0100_0000 => IpTosDscp::Cs2, + 0b0110_0000 => IpTosDscp::Cs3, + 0b1000_0000 => IpTosDscp::Cs4, + 0b1010_0000 => IpTosDscp::Cs5, + 0b1100_0000 => IpTosDscp::Cs6, + 0b1110_0000 => IpTosDscp::Cs7, + 0b0010_1000 => IpTosDscp::Af11, + 0b0011_0000 => IpTosDscp::Af12, + 0b0011_1000 => IpTosDscp::Af13, + 0b0100_1000 => IpTosDscp::Af21, + 0b0101_0000 => IpTosDscp::Af22, + 0b0101_1000 => IpTosDscp::Af23, + 0b0110_1000 => IpTosDscp::Af31, + 0b0111_0000 => IpTosDscp::Af32, + 0b0111_1000 => IpTosDscp::Af33, + 0b1000_1000 => IpTosDscp::Af41, + 0b1001_0000 => IpTosDscp::Af42, + 0b1001_1000 => IpTosDscp::Af43, + 0b1011_1000 => IpTosDscp::Ef, + 0b1011_0000 => IpTosDscp::VoiceAdmit, + 0b0000_0100 => IpTosDscp::Le, + _ => unreachable!(), + } + } +} + +/// The type-of-service field in an IP packet. +#[allow(clippy::module_name_repetitions)] +#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] +pub struct IpTos { + /// The DSCP (Differentiated Services Code Point) field. + dscp: IpTosDscp, + + /// The ECN (Explicit Congestion Notification) field. + ecn: IpTosEcn, +} + +impl From for IpTos { + fn from(v: IpTosEcn) -> Self { + Self { + dscp: IpTosDscp::default(), + ecn: v, + } + } +} +impl From for IpTos { + fn from(v: IpTosDscp) -> Self { + Self { + dscp: v, + ecn: IpTosEcn::default(), + } + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn iptosecn_into_u8() { + assert_eq!(u8::from(IpTosEcn::NotEct), 0b00); + assert_eq!(u8::from(IpTosEcn::Ect1), 0b01); + assert_eq!(u8::from(IpTosEcn::Ect0), 0b10); + assert_eq!(u8::from(IpTosEcn::Ce), 0b11); + } + + #[test] + fn u8_into_iptosecn() { + assert_eq!(IpTosEcn::from(0b00), IpTosEcn::NotEct); + assert_eq!(IpTosEcn::from(0b01), IpTosEcn::Ect1); + assert_eq!(IpTosEcn::from(0b10), IpTosEcn::Ect0); + assert_eq!(IpTosEcn::from(0b11), IpTosEcn::Ce); + } + + #[test] + fn iptosdscp_into_u8() { + assert_eq!(u8::from(IpTosDscp::Cs0), 0b0000_0000); + assert_eq!(u8::from(IpTosDscp::Cs1), 0b0010_0000); + assert_eq!(u8::from(IpTosDscp::Cs2), 0b0100_0000); + assert_eq!(u8::from(IpTosDscp::Cs3), 0b0110_0000); + assert_eq!(u8::from(IpTosDscp::Cs4), 0b1000_0000); + assert_eq!(u8::from(IpTosDscp::Cs5), 0b1010_0000); + assert_eq!(u8::from(IpTosDscp::Cs6), 0b1100_0000); + assert_eq!(u8::from(IpTosDscp::Cs7), 0b1110_0000); + assert_eq!(u8::from(IpTosDscp::Af11), 0b0010_1000); + assert_eq!(u8::from(IpTosDscp::Af12), 0b0011_0000); + assert_eq!(u8::from(IpTosDscp::Af13), 0b0011_1000); + assert_eq!(u8::from(IpTosDscp::Af21), 0b0100_1000); + assert_eq!(u8::from(IpTosDscp::Af22), 0b0101_0000); + assert_eq!(u8::from(IpTosDscp::Af23), 0b0101_1000); + assert_eq!(u8::from(IpTosDscp::Af31), 0b0110_1000); + assert_eq!(u8::from(IpTosDscp::Af32), 0b0111_0000); + assert_eq!(u8::from(IpTosDscp::Af33), 0b0111_1000); + assert_eq!(u8::from(IpTosDscp::Af41), 0b1000_1000); + assert_eq!(u8::from(IpTosDscp::Af42), 0b1001_0000); + assert_eq!(u8::from(IpTosDscp::Af43), 0b1001_1000); + assert_eq!(u8::from(IpTosDscp::Ef), 0b1011_1000); + assert_eq!(u8::from(IpTosDscp::VoiceAdmit), 0b1011_0000); + assert_eq!(u8::from(IpTosDscp::Le), 0b0000_0100); + } + + #[test] + fn u8_into_iptosdscp() { + assert_eq!(IpTosDscp::from(0b0000_0000), IpTosDscp::Cs0); + assert_eq!(IpTosDscp::from(0b0010_0000), IpTosDscp::Cs1); + assert_eq!(IpTosDscp::from(0b0100_0000), IpTosDscp::Cs2); + assert_eq!(IpTosDscp::from(0b0110_0000), IpTosDscp::Cs3); + assert_eq!(IpTosDscp::from(0b1000_0000), IpTosDscp::Cs4); + assert_eq!(IpTosDscp::from(0b1010_0000), IpTosDscp::Cs5); + assert_eq!(IpTosDscp::from(0b1100_0000), IpTosDscp::Cs6); + assert_eq!(IpTosDscp::from(0b1110_0000), IpTosDscp::Cs7); + assert_eq!(IpTosDscp::from(0b0010_1000), IpTosDscp::Af11); + assert_eq!(IpTosDscp::from(0b0011_0000), IpTosDscp::Af12); + assert_eq!(IpTosDscp::from(0b0011_1000), IpTosDscp::Af13); + assert_eq!(IpTosDscp::from(0b0100_1000), IpTosDscp::Af21); + assert_eq!(IpTosDscp::from(0b0101_0000), IpTosDscp::Af22); + assert_eq!(IpTosDscp::from(0b0101_1000), IpTosDscp::Af23); + assert_eq!(IpTosDscp::from(0b0110_1000), IpTosDscp::Af31); + assert_eq!(IpTosDscp::from(0b0111_0000), IpTosDscp::Af32); + assert_eq!(IpTosDscp::from(0b0111_1000), IpTosDscp::Af33); + assert_eq!(IpTosDscp::from(0b1000_1000), IpTosDscp::Af41); + assert_eq!(IpTosDscp::from(0b1001_0000), IpTosDscp::Af42); + assert_eq!(IpTosDscp::from(0b1001_1000), IpTosDscp::Af43); + assert_eq!(IpTosDscp::from(0b1011_1000), IpTosDscp::Ef); + assert_eq!(IpTosDscp::from(0b1011_0000), IpTosDscp::VoiceAdmit); + assert_eq!(IpTosDscp::from(0b0000_0100), IpTosDscp::Le); + } + + #[test] + fn iptosecn_into_iptos() { + let ecn = IpTosEcn::default(); + let iptos: IpTos = ecn.into(); + assert_eq!(iptos.dscp, IpTosDscp::default()); + assert_eq!(iptos.ecn, ecn); + } + + #[test] + fn iptosdscp_into_iptos() { + let dscp = IpTosDscp::default(); + let iptos: IpTos = dscp.into(); + assert_eq!(iptos.dscp, dscp); + assert_eq!(iptos.ecn, IpTosEcn::default()); + } +}