xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/batch_writer/quic_gso_batch_writer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
6 #define QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
7 
8 #include "quiche/quic/core/batch_writer/quic_batch_writer_base.h"
9 
10 namespace quic {
11 
12 // QuicGsoBatchWriter sends QUIC packets in batches, using UDP socket's generic
13 // segmentation offload(GSO) capability.
14 class QUICHE_EXPORT QuicGsoBatchWriter : public QuicUdpBatchWriter {
15  public:
16   explicit QuicGsoBatchWriter(int fd);
17 
18   // |clockid_for_release_time|: FQ qdisc requires CLOCK_MONOTONIC, EDF requires
19   // CLOCK_TAI.
20   QuicGsoBatchWriter(int fd, clockid_t clockid_for_release_time);
21 
SupportsReleaseTime()22   bool SupportsReleaseTime() const final { return supports_release_time_; }
23 
SupportsEcn()24   bool SupportsEcn() const override {
25     return GetQuicRestartFlag(quic_support_ect1);
26   }
27 
28   CanBatchResult CanBatch(const char* buffer, size_t buf_len,
29                           const QuicIpAddress& self_address,
30                           const QuicSocketAddress& peer_address,
31                           const PerPacketOptions* options,
32                           const QuicPacketWriterParams& params,
33                           uint64_t release_time) const override;
34 
35   FlushImplResult FlushImpl() override;
36 
37  protected:
38   // Test only constructor to forcefully enable release time.
39   struct QUICHE_EXPORT ReleaseTimeForceEnabler {};
40   QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
41                      int fd, clockid_t clockid_for_release_time,
42                      ReleaseTimeForceEnabler enabler);
43 
44   ReleaseTime GetReleaseTime(
45       const QuicPacketWriterParams& params) const override;
46 
47   // Get the current time in nanos from |clockid_for_release_time_|.
48   virtual uint64_t NowInNanosForReleaseTime() const;
49 
MaxSegments(size_t gso_size)50   static size_t MaxSegments(size_t gso_size) {
51     // Max segments should be the min of UDP_MAX_SEGMENTS(64) and
52     // (((64KB - sizeof(ip hdr) - sizeof(udp hdr)) / MSS) + 1), in the typical
53     // case of IPv6 packets with 1500-byte MTU, the result is
54     //         ((64KB - 40 - 8) / (1500 - 48)) + 1 = 46
55     // However, due a kernel bug, the limit is much lower for tiny gso_sizes.
56     return gso_size <= 2 ? 16 : 45;
57   }
58 
59   static const int kCmsgSpace = kCmsgSpaceForIp + kCmsgSpaceForSegmentSize +
60                                 kCmsgSpaceForTxTime + kCmsgSpaceForTOS;
61   static void BuildCmsg(QuicMsgHdr* hdr, const QuicIpAddress& self_address,
62                         uint16_t gso_size, uint64_t release_time,
63                         QuicEcnCodepoint ecn_codepoint);
64 
65   template <size_t CmsgSpace, typename CmsgBuilderT>
InternalFlushImpl(CmsgBuilderT cmsg_builder)66   FlushImplResult InternalFlushImpl(CmsgBuilderT cmsg_builder) {
67     QUICHE_DCHECK(!IsWriteBlocked());
68     QUICHE_DCHECK(!buffered_writes().empty());
69 
70     FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0),
71                               /*num_packets_sent=*/0, /*bytes_written=*/0};
72     WriteResult& write_result = result.write_result;
73 
74     int total_bytes = batch_buffer().SizeInUse();
75     const BufferedWrite& first = buffered_writes().front();
76     char cbuf[CmsgSpace];
77     QuicMsgHdr hdr(first.buffer, total_bytes, first.peer_address, cbuf,
78                    sizeof(cbuf));
79 
80     uint16_t gso_size = buffered_writes().size() > 1 ? first.buf_len : 0;
81     cmsg_builder(&hdr, first.self_address, gso_size, first.release_time,
82                  first.params.ecn_codepoint);
83 
84     write_result = QuicLinuxSocketUtils::WritePacket(fd(), hdr);
85     QUIC_DVLOG(1) << "Write GSO packet result: " << write_result
86                   << ", fd: " << fd()
87                   << ", self_address: " << first.self_address.ToString()
88                   << ", peer_address: " << first.peer_address.ToString()
89                   << ", num_segments: " << buffered_writes().size()
90                   << ", total_bytes: " << total_bytes
91                   << ", gso_size: " << gso_size
92                   << ", release_time: " << first.release_time;
93 
94     // All segments in a GSO packet share the same fate - if the write failed,
95     // none of them are sent, and it's not needed to call PopBufferedWrite().
96     if (write_result.status != WRITE_STATUS_OK) {
97       return result;
98     }
99 
100     result.num_packets_sent = buffered_writes().size();
101 
102     write_result.bytes_written = total_bytes;
103     result.bytes_written = total_bytes;
104 
105     batch_buffer().PopBufferedWrite(buffered_writes().size());
106 
107     QUIC_BUG_IF(quic_bug_12544_1, !buffered_writes().empty())
108         << "All packets should have been written on a successful return";
109     return result;
110   }
111 
112  private:
113   static std::unique_ptr<QuicBatchWriterBuffer> CreateBatchWriterBuffer();
114 
115   const clockid_t clockid_for_release_time_;
116   const bool supports_release_time_;
117 };
118 
119 }  // namespace quic
120 
121 #endif  // QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
122