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