// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0 > or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT >, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fmt::Debug;
use enum_map::
Enum ;
/// 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, Debug)]
#[ repr(u8)]
pub enum IpTosEcn {
#[ default]
/// Not-ECT, Not ECN-Capable Transport, RFC3168
NotEct =
0 b00,
/// ECT(1), ECN-Capable Transport(1), RFC8311 and RFC9331
Ect1 =
0 b01,
/// ECT(0), ECN-Capable Transport(0), RFC3168
Ect0 =
0 b10,
/// CE, Congestion Experienced, RFC3168
Ce =
0 b11,
}
impl From<IpTosEcn>
for u8 {
fn from(v: IpTosEcn) ->
Self {
v
as Self
}
}
impl From<u8>
for IpTosEcn {
fn from(v: u8) ->
Self {
match v &
0 b0000_0011 {
0 b00 =>
Self ::NotEct,
0 b01 =>
Self ::Ect1,
0 b10 =>
Self ::Ect0,
0 b11 =>
Self ::Ce,
_ => unreachable!(),
}
}
}
impl From<IpTos>
for IpTosEcn {
fn from(v: IpTos) ->
Self {
Self ::from(u8::from(v))
}
}
impl IpTosEcn {
#[ must_use]
pub const fn is_ecn_marked(&
self ) -> bool {
match self {
Self ::Ect0 |
Self ::Ect1 |
Self ::Ce =>
true ,
Self ::NotEct =>
false ,
}
}
}
/// 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, Debug)]
#[ repr(u8)]
pub enum IpTosDscp {
#[ default]
/// Class Selector 0, RFC2474
Cs0 =
0 b0000_0000,
/// Class Selector 1, RFC2474
Cs1 =
0 b0010_0000,
/// Class Selector 2, RFC2474
Cs2 =
0 b0100_0000,
/// Class Selector 3, RFC2474
Cs3 =
0 b0110_0000,
/// Class Selector 4, RFC2474
Cs4 =
0 b1000_0000,
/// Class Selector 5, RFC2474
Cs5 =
0 b1010_0000,
/// Class Selector 6, RFC2474
Cs6 =
0 b1100_0000,
/// Class Selector 7, RFC2474
Cs7 =
0 b1110_0000,
/// Assured Forwarding 11, RFC2597
Af11 =
0 b0010_1000,
/// Assured Forwarding 12, RFC2597
Af12 =
0 b0011_0000,
/// Assured Forwarding 13, RFC2597
Af13 =
0 b0011_1000,
/// Assured Forwarding 21, RFC2597
Af21 =
0 b0100_1000,
/// Assured Forwarding 22, RFC2597
Af22 =
0 b0101_0000,
/// Assured Forwarding 23, RFC2597
Af23 =
0 b0101_1000,
/// Assured Forwarding 31, RFC2597
Af31 =
0 b0110_1000,
/// Assured Forwarding 32, RFC2597
Af32 =
0 b0111_0000,
/// Assured Forwarding 33, RFC2597
Af33 =
0 b0111_1000,
/// Assured Forwarding 41, RFC2597
Af41 =
0 b1000_1000,
/// Assured Forwarding 42, RFC2597
Af42 =
0 b1001_0000,
/// Assured Forwarding 43, RFC2597
Af43 =
0 b1001_1000,
/// Expedited Forwarding, RFC3246
Ef =
0 b1011_1000,
/// Capacity-Admitted Traffic, RFC5865
VoiceAdmit =
0 b1011_0000,
/// Lower-Effort, RFC8622
Le =
0 b0000_0100,
}
impl From<IpTosDscp>
for u8 {
fn from(v: IpTosDscp) ->
Self {
v
as Self
}
}
impl From<u8>
for IpTosDscp {
fn from(v: u8) ->
Self {
match v &
0 b1111_1100 {
0 b0000_0000 =>
Self ::Cs0,
0 b0010_0000 =>
Self ::Cs1,
0 b0100_0000 =>
Self ::Cs2,
0 b0110_0000 =>
Self ::Cs3,
0 b1000_0000 =>
Self ::Cs4,
0 b1010_0000 =>
Self ::Cs5,
0 b1100_0000 =>
Self ::Cs6,
0 b1110_0000 =>
Self ::Cs7,
0 b0010_1000 =>
Self ::Af11,
0 b0011_0000 =>
Self ::Af12,
0 b0011_1000 =>
Self ::Af13,
0 b0100_1000 =>
Self ::Af21,
0 b0101_0000 =>
Self ::Af22,
0 b0101_1000 =>
Self ::Af23,
0 b0110_1000 =>
Self ::Af31,
0 b0111_0000 =>
Self ::Af32,
0 b0111_1000 =>
Self ::Af33,
0 b1000_1000 =>
Self ::Af41,
0 b1001_0000 =>
Self ::Af42,
0 b1001_1000 =>
Self ::Af43,
0 b1011_1000 =>
Self ::Ef,
0 b1011_0000 =>
Self ::VoiceAdmit,
0 b0000_0100 =>
Self ::Le,
_ => unreachable!(),
}
}
}
impl From<IpTos>
for IpTosDscp {
fn from(v: IpTos) ->
Self {
Self ::from(u8::from(v))
}
}
/// The type-of-service field in an IP packet.
#[ derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct IpTos(u8);
impl From<IpTosEcn>
for IpTos {
fn from(v: IpTosEcn) ->
Self {
Self (u8::from(v))
}
}
impl From<IpTosDscp>
for IpTos {
fn from(v: IpTosDscp) ->
Self {
Self (u8::from(v))
}
}
impl From<(IpTosDscp, IpTosEcn)>
for IpTos {
fn from(v: (IpTosDscp, IpTosEcn)) ->
Self {
Self (u8::from(v.
0 ) | u8::from(v.
1 ))
}
}
impl From<(IpTosEcn, IpTosDscp)>
for IpTos {
fn from(v: (IpTosEcn, IpTosDscp)) ->
Self {
Self (u8::from(v.
0 ) | u8::from(v.
1 ))
}
}
impl From<IpTos>
for u8 {
fn from(v: IpTos) ->
Self {
v.
0
}
}
impl From<u8>
for IpTos {
fn from(v: u8) ->
Self {
Self (v)
}
}
impl Debug
for IpTos {
fn fmt(&
self , f: &
mut std::fmt::Formatte
r<'_>) -> std::fmt::Result {
f.debug_tuple("IpTos" )
.field(&IpTosDscp::from(*self ))
.field(&IpTosEcn::from(*self ))
.finish()
}
}
impl IpTos {
pub fn set_ecn(&mut self , ecn: IpTosEcn) {
self .0 = u8::from(IpTosDscp::from(*self )) | u8::from(ecn);
}
pub fn set_dscp(&mut self , dscp: IpTosDscp) {
self .0 = u8::from(IpTosEcn::from(*self )) | u8::from(dscp);
}
#[ must_use]
pub fn is_ecn_marked(&self ) -> bool {
IpTosEcn::from(*self ).is_ecn_marked()
}
}
#[ cfg(test)]
mod tests {
use crate ::{IpTos, IpTosDscp, IpTosEcn};
#[ test]
fn iptosecn_into_u8() {
assert_eq!(u8::from(IpTosEcn::NotEct), 0 b00);
assert_eq!(u8::from(IpTosEcn::Ect1), 0 b01);
assert_eq!(u8::from(IpTosEcn::Ect0), 0 b10);
assert_eq!(u8::from(IpTosEcn::Ce), 0 b11);
}
#[ test]
fn u8_into_iptosecn() {
assert_eq!(IpTosEcn::from(0 b00), IpTosEcn::NotEct);
assert_eq!(IpTosEcn::from(0 b01), IpTosEcn::Ect1);
assert_eq!(IpTosEcn::from(0 b10), IpTosEcn::Ect0);
assert_eq!(IpTosEcn::from(0 b11), IpTosEcn::Ce);
}
#[ test]
fn iptosdscp_into_u8() {
assert_eq!(u8::from(IpTosDscp::Cs0), 0 b0000_0000);
assert_eq!(u8::from(IpTosDscp::Cs1), 0 b0010_0000);
assert_eq!(u8::from(IpTosDscp::Cs2), 0 b0100_0000);
assert_eq!(u8::from(IpTosDscp::Cs3), 0 b0110_0000);
assert_eq!(u8::from(IpTosDscp::Cs4), 0 b1000_0000);
assert_eq!(u8::from(IpTosDscp::Cs5), 0 b1010_0000);
assert_eq!(u8::from(IpTosDscp::Cs6), 0 b1100_0000);
assert_eq!(u8::from(IpTosDscp::Cs7), 0 b1110_0000);
assert_eq!(u8::from(IpTosDscp::Af11), 0 b0010_1000);
assert_eq!(u8::from(IpTosDscp::Af12), 0 b0011_0000);
assert_eq!(u8::from(IpTosDscp::Af13), 0 b0011_1000);
assert_eq!(u8::from(IpTosDscp::Af21), 0 b0100_1000);
assert_eq!(u8::from(IpTosDscp::Af22), 0 b0101_0000);
assert_eq!(u8::from(IpTosDscp::Af23), 0 b0101_1000);
assert_eq!(u8::from(IpTosDscp::Af31), 0 b0110_1000);
assert_eq!(u8::from(IpTosDscp::Af32), 0 b0111_0000);
assert_eq!(u8::from(IpTosDscp::Af33), 0 b0111_1000);
assert_eq!(u8::from(IpTosDscp::Af41), 0 b1000_1000);
assert_eq!(u8::from(IpTosDscp::Af42), 0 b1001_0000);
assert_eq!(u8::from(IpTosDscp::Af43), 0 b1001_1000);
assert_eq!(u8::from(IpTosDscp::Ef), 0 b1011_1000);
assert_eq!(u8::from(IpTosDscp::VoiceAdmit), 0 b1011_0000);
assert_eq!(u8::from(IpTosDscp::Le), 0 b0000_0100);
}
#[ test]
fn u8_into_iptosdscp() {
assert_eq!(IpTosDscp::from(0 b0000_0000), IpTosDscp::Cs0);
assert_eq!(IpTosDscp::from(0 b0010_0000), IpTosDscp::Cs1);
assert_eq!(IpTosDscp::from(0 b0100_0000), IpTosDscp::Cs2);
assert_eq!(IpTosDscp::from(0 b0110_0000), IpTosDscp::Cs3);
assert_eq!(IpTosDscp::from(0 b1000_0000), IpTosDscp::Cs4);
assert_eq!(IpTosDscp::from(0 b1010_0000), IpTosDscp::Cs5);
assert_eq!(IpTosDscp::from(0 b1100_0000), IpTosDscp::Cs6);
assert_eq!(IpTosDscp::from(0 b1110_0000), IpTosDscp::Cs7);
assert_eq!(IpTosDscp::from(0 b0010_1000), IpTosDscp::Af11);
assert_eq!(IpTosDscp::from(0 b0011_0000), IpTosDscp::Af12);
assert_eq!(IpTosDscp::from(0 b0011_1000), IpTosDscp::Af13);
assert_eq!(IpTosDscp::from(0 b0100_1000), IpTosDscp::Af21);
assert_eq!(IpTosDscp::from(0 b0101_0000), IpTosDscp::Af22);
assert_eq!(IpTosDscp::from(0 b0101_1000), IpTosDscp::Af23);
assert_eq!(IpTosDscp::from(0 b0110_1000), IpTosDscp::Af31);
assert_eq!(IpTosDscp::from(0 b0111_0000), IpTosDscp::Af32);
assert_eq!(IpTosDscp::from(0 b0111_1000), IpTosDscp::Af33);
assert_eq!(IpTosDscp::from(0 b1000_1000), IpTosDscp::Af41);
assert_eq!(IpTosDscp::from(0 b1001_0000), IpTosDscp::Af42);
assert_eq!(IpTosDscp::from(0 b1001_1000), IpTosDscp::Af43);
assert_eq!(IpTosDscp::from(0 b1011_1000), IpTosDscp::Ef);
assert_eq!(IpTosDscp::from(0 b1011_0000), IpTosDscp::VoiceAdmit);
assert_eq!(IpTosDscp::from(0 b0000_0100), IpTosDscp::Le);
}
#[ test]
fn iptosecn_into_iptos() {
let ecn = IpTosEcn::default();
let iptos_ecn: IpTos = ecn.into();
assert_eq!(u8::from(iptos_ecn), ecn as u8);
}
#[ test]
fn iptosdscp_into_iptos() {
let dscp = IpTosDscp::default();
let iptos_dscp: IpTos = dscp.into();
assert_eq!(u8::from(iptos_dscp), dscp as u8);
}
#[ test]
fn u8_to_iptos() {
let tos = 0 x8b;
let iptos: IpTos = (IpTosEcn::Ce, IpTosDscp::Af41).into();
assert_eq!(tos, u8::from(iptos));
assert_eq!(IpTos::from(tos), iptos);
}
#[ test]
fn iptos_to_iptosdscp() {
let tos = IpTos::from((IpTosDscp::Af41, IpTosEcn::NotEct));
let dscp = IpTosDscp::from(tos);
assert_eq!(dscp, IpTosDscp::Af41);
}
#[ test]
fn tos_modify_ecn() {
let mut iptos: IpTos = (IpTosDscp::Af41, IpTosEcn::NotEct).into();
iptos.set_ecn(IpTosEcn::Ce);
assert_eq!(u8::from(iptos), 0 b1000_1011);
}
#[ test]
fn tos_modify_dscp() {
let mut iptos: IpTos = (IpTosDscp::Af41, IpTosEcn::Ect1).into();
iptos.set_dscp(IpTosDscp::Le);
assert_eq!(u8::from(iptos), 0 b0000_0101);
}
#[ test]
fn iptos_is_ecn_marked() {
let iptos: IpTos = (IpTosDscp::Af41, IpTosEcn::Ce).into();
assert!(iptos.is_ecn_marked());
}
#[ test]
fn iptosecn_is_ecn_marked() {
assert!(IpTosEcn::Ce.is_ecn_marked());
assert!(!IpTosEcn::NotEct.is_ecn_marked());
}
}
Messung V0.5 in Prozent C=86 H=100 G=93
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-18)
¤
*© Formatika GbR, Deutschland