Line data Source code
1 : #pragma once 2 : 3 : #include <cstdint> 4 : #include <memory> 5 : 6 : #include "envoy/http/codec.h" 7 : #include "envoy/tcp/conn_pool.h" 8 : #include "envoy/upstream/thread_local_cluster.h" 9 : 10 : #include "source/common/buffer/watermark_buffer.h" 11 : #include "source/common/common/cleanup.h" 12 : #include "source/common/common/logger.h" 13 : #include "source/common/config/well_known_names.h" 14 : #include "source/common/network/utility.h" 15 : #include "source/common/router/upstream_request.h" 16 : #include "source/common/stream_info/stream_info_impl.h" 17 : 18 : #include "quiche/common/capsule.h" 19 : #include "quiche/common/simple_buffer_allocator.h" 20 : 21 : namespace Envoy { 22 : namespace Extensions { 23 : namespace Upstreams { 24 : namespace Http { 25 : namespace Udp { 26 : 27 : // Creates a UDP socket for a UDP upstream connection. When a new UDP upstream is requested by the 28 : // UpstreamRequest of Router, creates a UDPUpstream object and hands over the created socket to it. 29 : class UdpConnPool : public Router::GenericConnPool { 30 : public: 31 : UdpConnPool(Upstream::ThreadLocalCluster& thread_local_cluster, 32 : Upstream::LoadBalancerContext* ctx) 33 0 : : host_(thread_local_cluster.loadBalancer().chooseHost(ctx)) {} 34 : 35 : // Creates a UDPUpstream object for a new stream. 36 : void newStream(Router::GenericConnectionPoolCallbacks* callbacks) override; 37 : 38 0 : bool cancelAnyPendingStream() override { 39 : // Unlike TCP, UDP Upstreams do not have any pending streams because the upstream connection is 40 : // created immediately without a handshake. 41 0 : return false; 42 0 : } 43 : 44 0 : Upstream::HostDescriptionConstSharedPtr host() const override { return host_; } 45 : 46 0 : Network::SocketPtr createSocket(const Upstream::HostConstSharedPtr& host) { 47 0 : return std::make_unique<Network::SocketImpl>(Network::Socket::Type::Datagram, host->address(), 48 0 : /*remote_address=*/nullptr, 49 0 : Network::SocketCreationOptions{}); 50 0 : } 51 : 52 0 : bool valid() const override { return host_ != nullptr; } 53 : 54 : private: 55 : Upstream::HostConstSharedPtr host_; 56 : }; 57 : 58 : // Maintains data relevant to a UDP upstream connection including the socket for the upstream. 59 : // When a CONNECT-UDP request comes in, connects the socket to a node in the upstream cluster. 60 : // Also, adds appropriate header entries to the CONNECT-UDP response. 61 : class UdpUpstream : public Router::GenericUpstream, 62 : public Network::UdpPacketProcessor, 63 : public quiche::CapsuleParser::Visitor { 64 : public: 65 : UdpUpstream(Router::UpstreamToDownstream* upstream_to_downstream, Network::SocketPtr socket, 66 : Upstream::HostConstSharedPtr host, Event::Dispatcher& dispatcher); 67 : 68 : // GenericUpstream 69 : void encodeData(Buffer::Instance& data, bool end_stream) override; 70 0 : void encodeMetadata(const Envoy::Http::MetadataMapVector&) override {} 71 : Envoy::Http::Status encodeHeaders(const Envoy::Http::RequestHeaderMap&, bool end_stream) override; 72 0 : void encodeTrailers(const Envoy::Http::RequestTrailerMap&) override {} 73 0 : void readDisable(bool) override {} 74 : void resetStream() override; 75 0 : void setAccount(Buffer::BufferMemoryAccountSharedPtr) override {} 76 0 : const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; } 77 : 78 : // Network::UdpPacketProcessor 79 : // Handles data received from the UDP Upstream. 80 : void processPacket(Network::Address::InstanceConstSharedPtr local_address, 81 : Network::Address::InstanceConstSharedPtr peer_address, 82 : Buffer::InstancePtr buffer, MonotonicTime receive_time) override; 83 0 : uint64_t maxDatagramSize() const override { return Network::DEFAULT_UDP_MAX_DATAGRAM_SIZE; } 84 0 : void onDatagramsDropped(uint32_t dropped) override { 85 : // TODO(https://github.com/envoyproxy/envoy/issues/23564): Add statistics for CONNECT-UDP 86 : // upstreams. 87 0 : ENVOY_LOG_MISC(warn, "{} UDP datagrams were dropped.", dropped); 88 0 : datagrams_dropped_ += dropped; 89 0 : } 90 0 : size_t numPacketsExpectedPerEventLoop() const override { 91 0 : return Network::MAX_NUM_PACKETS_PER_EVENT_LOOP; 92 0 : } 93 0 : uint32_t numOfDroppedDatagrams() { return datagrams_dropped_; } 94 : 95 : // quiche::CapsuleParser::Visitor 96 : bool OnCapsule(const quiche::Capsule& capsule) override; 97 : void OnCapsuleParseFailure(absl::string_view error_message) override; 98 : 99 : private: 100 : void onSocketReadReady(); 101 : 102 : Router::UpstreamToDownstream* upstream_to_downstream_; 103 : const Network::SocketPtr socket_; 104 : Upstream::HostConstSharedPtr host_; 105 : Event::Dispatcher& dispatcher_; 106 : StreamInfo::BytesMeterSharedPtr bytes_meter_{std::make_shared<StreamInfo::BytesMeter>()}; 107 : quiche::CapsuleParser capsule_parser_{this}; 108 : quiche::SimpleBufferAllocator capsule_buffer_allocator_; 109 : uint32_t datagrams_dropped_ = 0; 110 : }; 111 : 112 : } // namespace Udp 113 : } // namespace Http 114 : } // namespace Upstreams 115 : } // namespace Extensions 116 : } // namespace Envoy