Skip to content

[QUIC] Integrate ECN feedback into congestion control #404

Description

@kcenon

Summary

Integrate ECN (Explicit Congestion Notification) feedback from ACK_ECN frames into the congestion controller for more responsive congestion detection.

Current State

  • ECN frame parsing is implemented (frame_type::ack_ecn)
  • ecn_counts structure exists in frame_types.h
  • congestion_controller::on_congestion_event() exists but not connected to ECN
  • Missing: ECN feedback processing in congestion control

Current ECN parsing:

struct ecn_counts {
    uint64_t ect0{0};   // ECT(0) count
    uint64_t ect1{0};   // ECT(1) count
    uint64_t ecn_ce{0}; // ECN-CE count (congestion experienced)
};

struct ack_frame {
    // ...
    std::optional<ecn_counts> ecn;  // Present for ACK_ECN frames
};

RFC 9002 Section 7.1: ECN Processing

  • ECN-CE marks indicate congestion without packet loss
  • More responsive than loss-based detection
  • Should trigger congestion response similar to packet loss

Proposed Implementation

1. ECN State Tracking

class ecn_tracker {
public:
    struct ecn_validation_state {
        bool capable{false};          // ECN capability validated
        bool testing{true};           // In testing phase
        uint64_t last_ect0{0};
        uint64_t last_ect1{0};
        uint64_t last_ecn_ce{0};
    };
    
    // Process received ECN counts
    auto process_ecn_counts(const ecn_counts& counts, 
                            uint64_t packets_acked) -> ecn_result;
    
    // Check if ECN is validated for use
    [[nodiscard]] bool is_ecn_capable() const;
    
    // Mark packets with ECN when sending
    [[nodiscard]] uint8_t get_ecn_marking() const;
    
private:
    ecn_validation_state state_;
};

enum class ecn_result {
    none,              // No congestion signal
    congestion_signal, // ECN-CE increased (congestion)
    ecn_failure,       // ECN validation failed
};

2. Integration Points

In loss_detector

auto loss_detector::on_ack_received(const ack_frame& ack, ...) 
    -> loss_detection_result 
{
    // Existing ACK processing...
    
    // NEW: Process ECN if present
    if (ack.ecn) {
        auto ecn_result = ecn_tracker_.process_ecn_counts(
            *ack.ecn, 
            acked_packets.size());
        result.ecn_signal = ecn_result;
    }
    
    return result;
}

In congestion_controller

auto congestion_controller::on_ecn_congestion(
    std::chrono::steady_clock::time_point sent_time) -> void 
{
    // Respond to ECN-CE same as packet loss
    // But only once per round trip
    if (!is_in_recovery(sent_time)) {
        enter_congestion_avoidance();
        ssthresh_ = std::max(cwnd_ / 2, minimum_window_);
        cwnd_ = ssthresh_;
        congestion_recovery_start_ = sent_time;
    }
}

In connection

auto connection::handle_ack(const ack_frame& ack) -> VoidResult {
    auto result = loss_detector_.on_ack_received(ack, level, now);
    
    // Handle losses
    for (const auto& lost : result.lost_packets) {
        congestion_controller_.on_packet_lost(lost);
    }
    
    // Handle acks
    for (const auto& acked : result.acked_packets) {
        congestion_controller_.on_packet_acked(acked, now);
    }
    
    // NEW: Handle ECN congestion signal
    if (result.ecn_signal == ecn_result::congestion_signal) {
        congestion_controller_.on_ecn_congestion(
            result.acked_packets.back().sent_time);
    }
    
    return common::ok();
}

3. ECN Validation (RFC 9000 Section 13.4)

// Validate ECN capability during handshake
bool ecn_tracker::validate_ecn(const ecn_counts& counts, 
                                uint64_t packets_sent) 
{
    // Check if peer is properly echoing ECN marks
    uint64_t total_marks = counts.ect0 + counts.ect1 + counts.ecn_ce;
    
    if (total_marks < packets_sent) {
        // ECN being stripped - disable ECN
        state_.capable = false;
        state_.testing = false;
        return false;
    }
    
    state_.capable = true;
    state_.testing = false;
    return true;
}

Tasks

  • Implement ecn_tracker class
  • Add ECN validation during handshake
  • Integrate ECN processing in loss_detector
  • Add on_ecn_congestion() to congestion_controller
  • Connect ECN signal to connection handling
  • Set IP ECN bits on outgoing packets
  • Unit tests for ECN tracking
  • Integration tests with ECN signals
  • Benchmark ECN vs loss-based detection

Acceptance Criteria

  • ECN-CE increments trigger congestion response
  • ECN capability validated during connection
  • Falls back gracefully when ECN not supported
  • No duplicate congestion responses per RTT
  • Outgoing packets marked with ECT(0)
  • All tests pass with TSAN/ASAN

Files to Create/Modify

  • New: include/kcenon/network/protocols/quic/ecn_tracker.h
  • New: src/protocols/quic/ecn_tracker.cpp
  • Modify: src/protocols/quic/loss_detector.cpp
  • Modify: src/protocols/quic/congestion_controller.cpp
  • Modify: src/protocols/quic/connection.cpp
  • New: tests/test_quic_ecn.cpp

Related

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions