s2n_quic_core/inet/
ecn.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4#[cfg(any(test, feature = "generator"))]
5use bolero_generator::prelude::*;
6
7//= https://www.rfc-editor.org/rfc/rfc3168#section-5
8//# This document specifies that the Internet provide a congestion
9//# indication for incipient congestion (as in RED and earlier work
10//# [RJ90]) where the notification can sometimes be through marking
11//# packets rather than dropping them.  This uses an ECN field in the IP
12//# header with two bits, making four ECN codepoints, '00' to '11'.  The
13//# ECN-Capable Transport (ECT) codepoints '10' and '01' are set by the
14//# data sender to indicate that the end-points of the transport protocol
15//# are ECN-capable; we call them ECT(0) and ECT(1) respectively.  The
16//# phrase "the ECT codepoint" in this documents refers to either of the
17//# two ECT codepoints.  Routers treat the ECT(0) and ECT(1) codepoints
18//# as equivalent.  Senders are free to use either the ECT(0) or the
19//# ECT(1) codepoint to indicate ECT, on a packet-by-packet basis.
20//#
21//# The use of both the two codepoints for ECT, ECT(0) and ECT(1), is
22//# motivated primarily by the desire to allow mechanisms for the data
23//# sender to verify that network elements are not erasing the CE
24//# codepoint, and that data receivers are properly reporting to the
25//# sender the receipt of packets with the CE codepoint set, as required
26//# by the transport protocol.  Guidelines for the senders and receivers
27//# to differentiate between the ECT(0) and ECT(1) codepoints will be
28//# addressed in separate documents, for each transport protocol.  In
29//# particular, this document does not address mechanisms for TCP end-
30//# nodes to differentiate between the ECT(0) and ECT(1) codepoints.
31//# Protocols and senders that only require a single ECT codepoint SHOULD
32//# use ECT(0).
33//#
34//# The not-ECT codepoint '00' indicates a packet that is not using ECN.
35//# The CE codepoint '11' is set by a router to indicate congestion to
36//# the end nodes.  Routers that have a packet arriving at a full queue
37//# drop the packet, just as they do in the absence of ECN.
38//#
39//#    +-----+-----+
40//#    | ECN FIELD |
41//#    +-----+-----+
42//#      ECT   CE         [Obsolete] RFC 2481 names for the ECN bits.
43//#       0     0         Not-ECT
44//#       0     1         ECT(1)
45//#       1     0         ECT(0)
46//#       1     1         CE
47//#
48//#    Figure 1: The ECN Field in IP.
49
50/// Explicit Congestion Notification
51#[repr(u8)]
52#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
53#[cfg_attr(any(test, feature = "generator"), derive(TypeGenerator))]
54#[cfg_attr(kani, derive(kani::Arbitrary))]
55pub enum ExplicitCongestionNotification {
56    /// The not-ECT codepoint '00' indicates a packet that is not using ECN.
57    NotEct = 0b00,
58
59    /// ECT(1) is set by the data sender to indicate that the end-points of the transport
60    /// protocol are ECN-capable.
61    Ect1 = 0b01,
62
63    /// ECT(0) is set by the data sender to indicate that the end-points of the transport
64    /// protocol are ECN-capable.
65    /// Protocols and senders that only require a single ECT codepoint SHOULD use ECT(0).
66    Ect0 = 0b10,
67
68    /// The CE codepoint '11' is set by a router to indicate congestion to the end nodes.
69    Ce = 0b11,
70}
71
72impl Default for ExplicitCongestionNotification {
73    #[inline]
74    fn default() -> Self {
75        Self::NotEct
76    }
77}
78
79impl ExplicitCongestionNotification {
80    /// Create a ExplicitCongestionNotification from the ECN field in the IP header
81    #[inline]
82    pub fn new(ecn_field: u8) -> Self {
83        match ecn_field & 0b11 {
84            0b00 => ExplicitCongestionNotification::NotEct,
85            0b01 => ExplicitCongestionNotification::Ect1,
86            0b10 => ExplicitCongestionNotification::Ect0,
87            0b11 => ExplicitCongestionNotification::Ce,
88            _ => unreachable!(),
89        }
90    }
91
92    /// Returns true if congestion was experienced by the peer
93    #[inline]
94    pub fn congestion_experienced(self) -> bool {
95        self == Self::Ce
96    }
97
98    /// Returns true if ECN is in use
99    #[inline]
100    pub fn using_ecn(self) -> bool {
101        self != Self::NotEct
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn new() {
111        for ecn in &[
112            ExplicitCongestionNotification::NotEct,
113            ExplicitCongestionNotification::Ect1,
114            ExplicitCongestionNotification::Ect0,
115            ExplicitCongestionNotification::Ce,
116        ] {
117            assert_eq!(*ecn, ExplicitCongestionNotification::new(*ecn as u8));
118        }
119    }
120
121    /// The most-significant 6 bits of the 8-bit traffic class field ECN markings are
122    /// read from are used for the differentiated services code point. This test
123    /// ensures we still parse ECN bits correctly even when the DSCP markings are present.
124    #[test]
125    fn dscp_markings() {
126        for i in 0..u8::MAX {
127            for ecn in &[
128                ExplicitCongestionNotification::NotEct,
129                ExplicitCongestionNotification::Ect1,
130                ExplicitCongestionNotification::Ect0,
131                ExplicitCongestionNotification::Ce,
132            ] {
133                assert_eq!(
134                    *ecn,
135                    ExplicitCongestionNotification::new((i << 2) | *ecn as u8)
136                );
137            }
138        }
139    }
140}