blob: f87e9f8e78d1c77dde1684143947e49838b68ce8 [file] [log] [blame]
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_
#include "quic/core/batch_writer/quic_batch_writer_base.h"
namespace quic {
// QuicGsoBatchWriter sends QUIC packets in batches, using UDP socket's generic
// segmentation offload(GSO) capability.
class QUIC_EXPORT_PRIVATE QuicGsoBatchWriter : public QuicUdpBatchWriter {
public:
explicit QuicGsoBatchWriter(int fd);
// |clockid_for_release_time|: FQ qdisc requires CLOCK_MONOTONIC, EDF requires
// CLOCK_TAI.
QuicGsoBatchWriter(int fd, clockid_t clockid_for_release_time);
bool SupportsReleaseTime() const final { return supports_release_time_; }
CanBatchResult CanBatch(const char* buffer,
size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
const PerPacketOptions* options,
uint64_t release_time) const override;
FlushImplResult FlushImpl() override;
protected:
// Test only constructor to forcefully enable release time.
struct QUIC_EXPORT_PRIVATE ReleaseTimeForceEnabler {};
QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
int fd,
clockid_t clockid_for_release_time,
ReleaseTimeForceEnabler enabler);
ReleaseTime GetReleaseTime(const PerPacketOptions* options) const override;
// Get the current time in nanos from |clockid_for_release_time_|.
virtual uint64_t NowInNanosForReleaseTime() const;
static size_t MaxSegments(size_t gso_size) {
// Max segments should be the min of UDP_MAX_SEGMENTS(64) and
// (((64KB - sizeof(ip hdr) - sizeof(udp hdr)) / MSS) + 1), in the typical
// case of IPv6 packets with 1500-byte MTU, the result is
// ((64KB - 40 - 8) / (1500 - 48)) + 1 = 46
// However, due a kernel bug, the limit is much lower for tiny gso_sizes.
return gso_size <= 2 ? 16 : 45;
}
static const int kCmsgSpace =
kCmsgSpaceForIp + kCmsgSpaceForSegmentSize + kCmsgSpaceForTxTime;
static void BuildCmsg(QuicMsgHdr* hdr,
const QuicIpAddress& self_address,
uint16_t gso_size,
uint64_t release_time);
template <size_t CmsgSpace, typename CmsgBuilderT>
FlushImplResult InternalFlushImpl(CmsgBuilderT cmsg_builder) {
QUICHE_DCHECK(!IsWriteBlocked());
QUICHE_DCHECK(!buffered_writes().empty());
FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0),
/*num_packets_sent=*/0, /*bytes_written=*/0};
WriteResult& write_result = result.write_result;
int total_bytes = batch_buffer().SizeInUse();
const BufferedWrite& first = buffered_writes().front();
char cbuf[CmsgSpace];
QuicMsgHdr hdr(first.buffer, total_bytes, first.peer_address, cbuf,
sizeof(cbuf));
uint16_t gso_size = buffered_writes().size() > 1 ? first.buf_len : 0;
cmsg_builder(&hdr, first.self_address, gso_size, first.release_time);
write_result = QuicLinuxSocketUtils::WritePacket(fd(), hdr);
QUIC_DVLOG(1) << "Write GSO packet result: " << write_result
<< ", fd: " << fd()
<< ", self_address: " << first.self_address.ToString()
<< ", peer_address: " << first.peer_address.ToString()
<< ", num_segments: " << buffered_writes().size()
<< ", total_bytes: " << total_bytes
<< ", gso_size: " << gso_size
<< ", release_time: " << first.release_time;
// All segments in a GSO packet share the same fate - if the write failed,
// none of them are sent, and it's not needed to call PopBufferedWrite().
if (write_result.status != WRITE_STATUS_OK) {
return result;
}
result.num_packets_sent = buffered_writes().size();
write_result.bytes_written = total_bytes;
result.bytes_written = total_bytes;
batch_buffer().PopBufferedWrite(buffered_writes().size());
QUIC_BUG_IF(quic_bug_12544_1, !buffered_writes().empty())
<< "All packets should have been written on a successful return";
return result;
}
private:
static std::unique_ptr<QuicBatchWriterBuffer> CreateBatchWriterBuffer();
const clockid_t clockid_for_release_time_;
const bool supports_release_time_;
};
} // namespace quic
#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_