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