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}