quic: add support for future ECN marking · nodejs/node@9560084 · GitHub
Skip to content

Commit 9560084

Browse files
jasnelladuh95
authored andcommitted
quic: add support for future ECN marking
Set up for when libuv eventually supports ECN marking. Pass the ECN marking stuff into ngtcp2. Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode:Opus 4.6 PR-URL: #63267 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 2b3ff8a commit 9560084

6 files changed

Lines changed: 77 additions & 24 deletions

File tree

src/quic/application.cc

Lines changed: 22 additions & 13 deletions

src/quic/application.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,11 @@ class Session::Application : public MemoryRetainer {
269269
uint8_t* dest,
270270
size_t destlen);
271271

272-
// Write the given stream_data into the buffer.
272+
// Write the given stream_data into the buffer. The PacketInfo out-param
273+
// is populated by ngtcp2 with per-packet metadata (e.g., ECN codepoint)
274+
// that should be applied when sending the packet.
273275
ssize_t WriteVStream(PathStorage* path,
276+
PacketInfo* pi,
274277
uint8_t* buf,
275278
ssize_t* ndatalen,
276279
size_t max_packet_size,

src/quic/data.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,40 @@ namespace node::quic {
1919
template <typename T>
2020
concept OneByteType = sizeof(T) == 1;
2121

22+
// Lightweight wrapper around ngtcp2_pkt_info. Insulates the Node.js QUIC
23+
// code from the ngtcp2 struct layout and provides a clean API boundary
24+
// for per-packet metadata (currently ECN codepoint; may grow as ngtcp2
25+
// and libuv evolve).
26+
//
27+
// Default-constructed PacketInfo is zero-initialized, which ngtcp2 treats
28+
// as ECN Not-ECT — identical to passing nullptr for the pkt_info parameter.
29+
class PacketInfo final {
30+
public:
31+
// ECN codepoints as defined by RFC 3168.
32+
enum class Ecn : uint32_t {
33+
NOT_ECT = 0, // Not ECN-Capable Transport
34+
ECT_1 = 1, // ECN-Capable Transport(1)
35+
ECT_0 = 2, // ECN-Capable Transport(0)
36+
CE = 3, // Congestion Experienced
37+
};
38+
39+
PacketInfo() : info_{} {}
40+
explicit PacketInfo(const ngtcp2_pkt_info& info) : info_(info) {}
41+
42+
// ECN codepoint for this packet. When libuv gains per-packet ECN
43+
// reporting, populate via set_ecn() from the receive metadata
44+
// before passing to ReadPacket().
45+
Ecn ecn() const { return static_cast<Ecn>(info_.ecn); }
46+
void set_ecn(Ecn ecn) { info_.ecn = static_cast<uint32_t>(ecn); }
47+
48+
// Conversion operators for ngtcp2 API calls.
49+
operator const ngtcp2_pkt_info*() const { return &info_; }
50+
operator ngtcp2_pkt_info*() { return &info_; }
51+
52+
private:
53+
ngtcp2_pkt_info info_;
54+
};
55+
2256
struct Path final : public ngtcp2_path {
2357
explicit Path(const SocketAddress& local, const SocketAddress& remote);
2458
Path(Path&& other) noexcept = default;

src/quic/packet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class Packet final {
6868
size_t length() const { return length_; }
6969
size_t capacity() const { return capacity_; }
7070
const SocketAddress& destination() const { return destination_; }
71+
const PacketInfo& pkt_info() const { return pkt_info_; }
72+
void set_pkt_info(const PacketInfo& pi) { pkt_info_ = pi; }
7173
Listener* listener() const { return listener_; }
7274

7375
// Redirect the packet to a different endpoint for cross-endpoint sends
@@ -148,6 +150,7 @@ class Packet final {
148150
Listener* listener_;
149151

150152
// Touched at send time.
153+
PacketInfo pkt_info_;
151154
SocketAddress destination_;
152155

153156
// Only touched by libuv during uv_udp_send and in the send callback.

src/quic/session.cc

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,19 +2103,21 @@ void Session::SetLastError(QuicError&& error) {
21032103

21042104
bool Session::Receive(Store&& store,
21052105
const SocketAddress& local_address,
2106-
const SocketAddress& remote_address) {
2106+
const SocketAddress& remote_address,
2107+
const PacketInfo& pkt_info) {
21072108
// Convenience wrapper: reads the packet and immediately triggers
21082109
// SendPendingData. Used by paths that need an immediate response
21092110
// (e.g., Endpoint::Connect for client Initial packets).
21102111
// The hot receive path uses ReadPacket() directly with deferred
21112112
// flush via BindingData's uv_check callback.
21122113
SendPendingDataScope send_scope(this);
2113-
return ReadPacket(std::move(store), local_address, remote_address);
2114+
return ReadPacket(std::move(store), local_address, remote_address, pkt_info);
21142115
}
21152116

21162117
bool Session::ReadPacket(Store&& store,
21172118
const SocketAddress& local_address,
2118-
const SocketAddress& remote_address) {
2119+
const SocketAddress& remote_address,
2120+
const PacketInfo& pkt_info) {
21192121
DCHECK(!is_destroyed());
21202122
impl_->remote_address_ = remote_address;
21212123

@@ -2137,12 +2139,12 @@ bool Session::ReadPacket(Store&& store,
21372139
int err;
21382140
{
21392141
NgTcp2CallbackScope callback_scope(this);
2140-
// ECN codepoint (ngtcp2_pkt_info.ecn) is not yet populated because
2141-
// libuv does not currently deliver per-packet ECN metadata. When
2142-
// libuv gains ECN receive reporting, the pkt_info should be
2143-
// populated from the per-packet metadata and passed through here.
2142+
// The PacketInfo carries per-packet metadata (currently ECN codepoint).
2143+
// When libuv gains per-packet ECN reporting, the caller should
2144+
// populate pkt_info from the receive metadata before calling
2145+
// ReadPacket().
21442146
err = ngtcp2_conn_read_pkt(
2145-
*this, &path, nullptr, vec.base, vec.len, uv_hrtime());
2147+
*this, &path, pkt_info, vec.base, vec.len, uv_hrtime());
21462148
}
21472149
if (is_destroyed()) return false;
21482150

src/quic/session.h

Lines changed: 4 additions & 2 deletions

0 commit comments

Comments
 (0)