Line data Source code
1 : #include "source/common/quic/udp_gso_batch_writer.h" 2 : 3 : #include "source/common/network/io_socket_error_impl.h" 4 : #include "source/common/quic/envoy_quic_utils.h" 5 : 6 : namespace Envoy { 7 : namespace Quic { 8 : namespace { 9 0 : Api::IoCallUint64Result convertQuicWriteResult(quic::WriteResult quic_result, size_t payload_len) { 10 0 : switch (quic_result.status) { 11 0 : case quic::WRITE_STATUS_OK: 12 0 : if (quic_result.bytes_written == 0) { 13 0 : ENVOY_LOG_MISC(trace, "sendmsg successful, message buffered to send"); 14 0 : } else { 15 0 : ENVOY_LOG_MISC(trace, "sendmsg successful, flushed bytes {}", quic_result.bytes_written); 16 0 : } 17 : // Return payload_len as rc & nullptr as error on success 18 0 : return {/*rc=*/payload_len, 19 0 : /*err=*/Api::IoError::none()}; 20 0 : case quic::WRITE_STATUS_BLOCKED_DATA_BUFFERED: 21 : // Data was buffered, Return payload_len as rc & nullptr as error 22 0 : ENVOY_LOG_MISC(trace, "sendmsg blocked, message buffered to send"); 23 0 : return {/*rc=*/payload_len, 24 0 : /*err=*/Api::IoError::none()}; 25 0 : case quic::WRITE_STATUS_BLOCKED: 26 : // Writer blocked, return error 27 0 : ENVOY_LOG_MISC(trace, "sendmsg blocked, message not buffered"); 28 0 : return {/*rc=*/0, 29 0 : /*err=*/Network::IoSocketError::getIoSocketEagainError()}; 30 0 : default: 31 : // Write Failed, return {0 and error_code} 32 0 : ENVOY_LOG_MISC(trace, "sendmsg failed with error code {}", 33 0 : static_cast<int>(quic_result.error_code)); 34 0 : return {/*rc=*/0, 35 0 : /*err=*/Network::IoSocketError::create(quic_result.error_code)}; 36 0 : } 37 0 : } 38 : 39 : } // namespace 40 : 41 : // Initialize QuicGsoBatchWriter, set io_handle_ and stats_ 42 : UdpGsoBatchWriter::UdpGsoBatchWriter(Network::IoHandle& io_handle, Stats::Scope& scope) 43 0 : : quic::QuicGsoBatchWriter(io_handle.fdDoNotUse()), stats_(generateStats(scope)) {} 44 : 45 : Api::IoCallUint64Result 46 : UdpGsoBatchWriter::writePacket(const Buffer::Instance& buffer, const Network::Address::Ip* local_ip, 47 0 : const Network::Address::Instance& peer_address) { 48 : // Convert received parameters to relevant forms 49 0 : quic::QuicSocketAddress peer_addr = envoyIpAddressToQuicSocketAddress(peer_address.ip()); 50 0 : quic::QuicSocketAddress self_addr = envoyIpAddressToQuicSocketAddress(local_ip); 51 0 : ASSERT(buffer.getRawSlices().size() == 1); 52 0 : size_t payload_len = static_cast<size_t>(buffer.frontSlice().len_); 53 : 54 : // TODO(yugant): Currently we do not use PerPacketOptions with Quic, we may want to 55 : // specify this parameter here at a later stage. 56 0 : quic::QuicPacketWriterParams params; 57 0 : quic::WriteResult quic_result = WritePacket(static_cast<char*>(buffer.frontSlice().mem_), 58 0 : payload_len, self_addr.host(), peer_addr, 59 0 : /*quic::PerPacketOptions=*/nullptr, params); 60 0 : updateUdpGsoBatchWriterStats(quic_result); 61 : 62 0 : return convertQuicWriteResult(quic_result, payload_len); 63 0 : } 64 : 65 0 : uint64_t UdpGsoBatchWriter::getMaxPacketSize(const Network::Address::Instance& peer_address) const { 66 0 : quic::QuicSocketAddress peer_addr = envoyIpAddressToQuicSocketAddress(peer_address.ip()); 67 0 : return static_cast<uint64_t>(GetMaxPacketSize(peer_addr)); 68 0 : } 69 : 70 : Network::UdpPacketWriterBuffer 71 : UdpGsoBatchWriter::getNextWriteLocation(const Network::Address::Ip* local_ip, 72 0 : const Network::Address::Instance& peer_address) { 73 0 : quic::QuicSocketAddress peer_addr = envoyIpAddressToQuicSocketAddress(peer_address.ip()); 74 0 : quic::QuicSocketAddress self_addr = envoyIpAddressToQuicSocketAddress(local_ip); 75 0 : quic::QuicPacketBuffer quic_buf = GetNextWriteLocation(self_addr.host(), peer_addr); 76 0 : return {reinterpret_cast<uint8_t*>(quic_buf.buffer), Network::UdpMaxOutgoingPacketSize, 77 0 : quic_buf.release_buffer}; 78 0 : } 79 : 80 0 : Api::IoCallUint64Result UdpGsoBatchWriter::flush() { 81 0 : quic::WriteResult quic_result = Flush(); 82 0 : updateUdpGsoBatchWriterStats(quic_result); 83 : 84 0 : return convertQuicWriteResult(quic_result, /*payload_len=*/0); 85 0 : } 86 : 87 0 : void UdpGsoBatchWriter::updateUdpGsoBatchWriterStats(quic::WriteResult quic_result) { 88 0 : if (quic_result.status == quic::WRITE_STATUS_OK && quic_result.bytes_written > 0) { 89 0 : if (gso_size_ > 0u) { 90 0 : uint64_t num_pkts_in_batch = 91 0 : std::ceil(static_cast<float>(quic_result.bytes_written) / gso_size_); 92 0 : stats_.pkts_sent_per_batch_.recordValue(num_pkts_in_batch); 93 0 : } 94 0 : stats_.total_bytes_sent_.add(quic_result.bytes_written); 95 0 : } 96 0 : stats_.internal_buffer_size_.set(batch_buffer().SizeInUse()); 97 0 : gso_size_ = buffered_writes().empty() ? 0u : buffered_writes().front().buf_len; 98 0 : } 99 : 100 0 : UdpGsoBatchWriterStats UdpGsoBatchWriter::generateStats(Stats::Scope& scope) { 101 0 : return { 102 0 : UDP_GSO_BATCH_WRITER_STATS(POOL_COUNTER(scope), POOL_GAUGE(scope), POOL_HISTOGRAM(scope))}; 103 0 : } 104 : 105 : Network::UdpPacketWriterPtr 106 0 : UdpGsoBatchWriterFactory::createUdpPacketWriter(Network::IoHandle& io_handle, Stats::Scope& scope) { 107 0 : return std::make_unique<UdpGsoBatchWriter>(io_handle, scope); 108 0 : } 109 : 110 : } // namespace Quic 111 : } // namespace Envoy